home *** CD-ROM | disk | FTP | other *** search
/ CD BIT 75 / CD BIT 75.iso / Software / SinfoSeguros / MSDE / Setup / SqlRun.cab / replmerg.sql.24170C3F_A9E4_47C1_8DFE_FD79C2714697 < prev    next >
Encoding:
Text File  |  2002-12-17  |  1.0 MB  |  30,776 lines

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1. /*
  2. ** Copyright Microsoft, Inc. 1998-2000
  3. ** All Rights Reserved.
  4. */
  5.  
  6. set nocount on
  7. go
  8.  
  9. execute dbo.sp_configure 'update',1
  10. go
  11. reconfigure with override
  12. go
  13.  
  14. set ANSI_NULLS off
  15. go
  16.  
  17. use master
  18. go
  19.  
  20. dump tran master with no_log
  21. go
  22.  
  23.  
  24.  
  25. /* 
  26. ** Drop the stored procedures in this script using the old dropping SP 
  27. ** and then drop itself
  28. */
  29. if exists (select * from sysobjects
  30.     where type = 'P '
  31.             and name = 'sp_MSdrop_rlcore')
  32. begin
  33.     drop procedure sp_MSdrop_rlcore
  34. end
  35.  
  36. /*
  37. ** Create stored procedures to drop the stored procedures
  38. ** created by this script
  39. */
  40.  
  41. raiserror('Creating procedure sp_MSdrop_rlcore', 0,1)
  42. GO
  43. create procedure sp_MSdrop_rlcore
  44. as
  45.  
  46.     if exists (select * from sysobjects
  47.             where type = 'P'
  48.                 and name = 'sp_MSguidtostr')
  49.         drop procedure sp_MSguidtostr
  50.  
  51.     if exists (select * from sysobjects
  52.             where type = 'P'
  53.                 and name = 'sp_MShelpdestowner')
  54.         drop procedure sp_MShelpdestowner
  55.  
  56.     if exists (select * from sysobjects
  57.             where type = 'P'
  58.                 and name = 'sp_MSchangeobjectowner')
  59.         drop procedure sp_MSchangeobjectowner
  60.  
  61.     if exists (select * from sysobjects
  62.             where type = 'P'
  63.                 and name = 'sp_MSgetcolumnlist')
  64.         drop procedure sp_MSgetcolumnlist
  65.  
  66.     if exists (select * from sysobjects
  67.             where type = 'P'
  68.                 and name = 'sp_MSgetconflicttablename')
  69.         drop procedure sp_MSgetconflicttablename
  70.  
  71.     if exists (select * from sysobjects
  72.             where type = 'P'
  73.                 and name = 'sp_MSuniquetempname')
  74.         drop procedure sp_MSuniquetempname
  75.  
  76.     if exists (select * from sysobjects
  77.             where type = 'P'
  78.                 and name = 'sp_MSuniqueobjectname')
  79.         drop procedure sp_MSuniqueobjectname
  80.  
  81.     if exists (select * from sysobjects
  82.             where type = 'P'
  83.                 and name = 'sp_MSfillupmissingcols')
  84.         drop procedure sp_MSfillupmissingcols
  85.  
  86.     if exists (select * from sysobjects
  87.             where type = 'P'
  88.                 and name = 'sp_MSaddguidcolumn')
  89.         drop procedure sp_MSaddguidcolumn
  90.  
  91.     if exists (select * from sysobjects
  92.             where type = 'P'
  93.                 and name = 'sp_MSprepare_mergearticle')
  94.         drop procedure sp_MSprepare_mergearticle
  95.  
  96.     if exists (select * from sysobjects
  97.             where type = 'P'
  98.                 and name = 'sp_MSuniquecolname')
  99.         drop procedure sp_MSuniquecolname
  100.  
  101.     if exists (select * from sysobjects
  102.             where type = 'P'
  103.                 and name = 'sp_MSaddguidindex')
  104.         drop procedure sp_MSaddguidindex
  105.  
  106.     if exists (select * from sysobjects
  107.             where type = 'P'
  108.                 and name = 'sp_MSrefcnt')
  109.         drop procedure sp_MSrefcnt
  110.     
  111.     if exists (select * from sysobjects
  112.             where type = 'P'
  113.                 and name = 'sp_MSgentablenickname')
  114.         drop procedure sp_MSgentablenickname
  115.     
  116.     if exists (select * from sysobjects
  117.             where type = 'P'
  118.                 and name = 'sp_MStablenickname')
  119.         drop procedure sp_MStablenickname
  120.     
  121.     if exists (select * from sysobjects
  122.         where type = 'P'
  123.             and name = 'sp_MStablenamefromnick')
  124.         drop procedure sp_MStablenamefromnick
  125.  
  126.     if exists (select * from sysobjects
  127.             where type = 'P'
  128.                 and name = 'sp_MSgetmakegenerationapplock')
  129.         drop procedure sp_MSgetmakegenerationapplock
  130.  
  131.     if exists (select * from sysobjects
  132.         where type = 'P'
  133.             and name = 'sp_MSreleasemakegenerationapplock')
  134.         drop procedure sp_MSreleasemakegenerationapplock
  135.  
  136.     if exists (select * from sysobjects
  137.         where type = 'P'
  138.             and name = 'sp_MSmakegeneration')
  139.         drop procedure sp_MSmakegeneration
  140.  
  141.     if exists (select * from sysobjects
  142.             where type = 'P'
  143.                 and name = 'sp_MSfixlineageversions')
  144.         drop procedure sp_MSfixlineageversions
  145.     
  146.     if exists (select * from sysobjects
  147.             where type = 'P'
  148.                 and name = 'sp_MSaddupdatetrigger')
  149.         drop procedure sp_MSaddupdatetrigger
  150.     
  151.     if exists (select * from sysobjects
  152.             where type = 'P'
  153.                 and name = 'sp_MSaddmergetriggers')
  154.         drop procedure sp_MSaddmergetriggers
  155.     
  156.     if exists (select * from sysobjects
  157.                 where type = 'P' and
  158.                 name = 'sp_MSmaptype')
  159.         drop procedure sp_MSmaptype 
  160.  
  161.     if exists (select * from sysobjects
  162.                 where type = 'P' and
  163.                 name = 'sp_MSquerysubtype')
  164.         drop procedure sp_MSquerysubtype 
  165.  
  166.     if exists( select * from sysobjects where type = 'P ' and name = 'sp_showrowreplicainfo')
  167.     begin
  168.         drop procedure sp_showrowreplicainfo
  169.     end
  170.  
  171.     if exists( select * from sysobjects where type = 'P ' and name = 'sp_MSsethighestversion')
  172.     begin
  173.         drop procedure sp_MSsethighestversion
  174.     end
  175.  
  176.     if exists( select * from sysobjects where type = 'P ' and name = 'sp_mergemetadataretentioncleanup')
  177.     begin
  178.         drop procedure sp_mergemetadataretentioncleanup
  179.     end
  180.  
  181.     if exists( select * from sysobjects where type = 'P ' and name = 'sp_MSpurgecontentsorphans')
  182.     begin
  183.         drop procedure sp_MSpurgecontentsorphans
  184.     end
  185.     
  186.     if exists( select * from sysobjects where type = 'P ' and name = 'sp_MScleanup_zeroartnick_genhistory')
  187.     begin
  188.         drop procedure sp_MScleanup_zeroartnick_genhistory
  189.     end
  190.     
  191.     if exists( select * from sysobjects where type = 'P ' and name = 'sp_MSdelete_specifiedcontents')
  192.     begin
  193.         drop procedure sp_MSdelete_specifiedcontents
  194.     end
  195.  
  196. go
  197. exec dbo.sp_MS_marksystemobject sp_MSdrop_rlcore
  198. go
  199. exec dbo.sp_MSdrop_rlcore
  200. go
  201.  
  202. dump tran master with no_log
  203. go
  204.  
  205. raiserror('Creating procedure sp_MSguidtostr', 0, 1)
  206. GO
  207.  
  208.  
  209. create proc sp_MSguidtostr (@guid uniqueidentifier, @mystr nvarchar(32) output)
  210.     as
  211. declare @guidstr nvarchar(36)
  212. set @guidstr = convert(nchar(36), @guid)
  213. set @mystr = substring(@guidstr, 1, 8) + substring(@guidstr, 10, 4) +
  214.     substring(@guidstr, 15, 4)+ substring(@guidstr, 20, 4)+ substring(@guidstr, 25, 12)
  215. go
  216. exec dbo.sp_MS_marksystemobject sp_MSguidtostr
  217. go
  218.  
  219. raiserror('Creating procedure sp_MSgetconflicttablename', 0,1)
  220. GO
  221.  
  222. CREATE PROCEDURE sp_MSgetconflicttablename
  223. @publication sysname,
  224. @source_object nvarchar(520),
  225. @conflict_table sysname = NULL OUTPUT
  226. AS
  227.  
  228. declare @objid                 int
  229. declare @retcode            int
  230. declare @current_conflict    sysname
  231. declare @object_name        sysname
  232. declare @name_out            sysname
  233. declare @pubid                uniqueidentifier
  234. declare @article            sysname
  235. declare @tablename          sysname
  236. declare @ownername          sysname
  237.  
  238. -- Security check
  239. exec @retcode= dbo.sp_MSreplcheck_publish
  240. if @@error <> 0 or @retcode <> 0 return (1)
  241.  
  242. select @tablename = null
  243. select @ownername = null
  244.  
  245. select @pubid=pubid from sysmergepublications where name=@publication and publisher=@@SERVERNAME and publisher_db=db_name()
  246.  
  247. select @objid = object_id(@source_object)
  248.  
  249. -- Raise error if objid is still null at this point
  250. if @objid is null
  251. begin
  252.     declare @db_name sysname
  253.     select @db_name = db_name()
  254.     raiserror(15009,16, -1,@source_object,@db_name)
  255.     return 1  
  256. end
  257. select @article=name, @current_conflict = conflict_table from sysmergearticles where objid = @objid and pubid=@pubid
  258. if @current_conflict is not NULL
  259.     begin
  260.         if @conflict_table is NULL
  261.             select @current_conflict
  262.         else    
  263.             select @conflict_table = @current_conflict
  264.         return (0)
  265.     end
  266.  
  267. if len(@publication) + len(@article) > 118         -- SYSNAME minus 'conflict_'
  268.     select @object_name = 'conflict_' + convert(nvarchar(59), @publication) + '_' + convert(nvarchar(59), @article)
  269. else
  270.     select @object_name = 'conflict_' + @publication + '_' + @article
  271. exec @retcode = dbo.sp_MSuniqueobjectname @object_name, @conflict_table OUTPUT
  272.  
  273. GO
  274.  
  275. exec dbo.sp_MS_marksystemobject sp_MSgetconflicttablename
  276. go
  277. grant exec on dbo.sp_MSgetconflicttablename to public
  278. go
  279.  
  280. raiserror('Creating procedure sp_MSuniqueobjectname', 0,1)
  281. GO
  282.  
  283. CREATE PROCEDURE sp_MSuniqueobjectname 
  284.     @name_in sysname,
  285.      @name_out sysname = NULL output
  286. AS
  287.  
  288.      declare @name_out_local sysname
  289.     declare @subschars         sysname
  290.     declare @curchar         nchar(1)
  291.     declare @substidx         int
  292.     declare @pos             int
  293.  
  294.     select @subschars = 'abcdefghijklmnopqrstuvwxyz'
  295.     select @name_out_local = @name_in
  296.  
  297.  
  298.     select @substidx = 0
  299.     select @pos = 1
  300.  
  301.     while exists (select * from sysobjects where name = @name_out_local)
  302.         begin
  303.         if @substidx > 25 
  304.             begin
  305.             select @pos = @pos + 1
  306.             select @substidx = 1
  307.             end
  308.         else
  309.             select @substidx = @substidx + 1
  310.         select @curchar = substring(@subschars, @substidx, 1)
  311.         select @name_out_local = stuff(@name_out_local, @pos, 1, @curchar)
  312.         end
  313.  
  314.     if @name_out IS NULL
  315.         select @name_out_local
  316.     else
  317.         select @name_out = @name_out_local
  318.  
  319.     return (0)
  320. GO
  321.  
  322. exec dbo.sp_MS_marksystemobject sp_MSuniqueobjectname 
  323. go
  324.  
  325.  
  326. raiserror('Creating procedure sp_MSuniquetempname', 0,1)
  327. GO
  328.  
  329. CREATE PROCEDURE sp_MSuniquetempname @name_in sysname,
  330.      @name_out sysname output
  331. AS
  332.  
  333.     declare @subschars nvarchar(26)
  334.     declare @curchar nchar(1)
  335.     declare @substidx int
  336.     declare @pos int
  337.     declare @saverr int
  338.  
  339.     select @subschars = 'abcdefghijklmnopqrstuvwxyz'
  340.     select @saverr = @@error
  341.     if (@saverr <> 0)
  342.         goto EXIT_LABEL
  343.     select @name_out = @name_in
  344.     select @saverr = @@error
  345.     if (@saverr <> 0)
  346.         goto EXIT_LABEL
  347.  
  348.     select @saverr = @@error
  349.     if (@saverr <> 0)
  350.         goto EXIT_LABEL
  351.     select @substidx = 0
  352.     select @pos = 3
  353.  
  354.     while exists (select * from tempdb..sysobjects where name = @name_out)
  355.         begin
  356.             if @substidx > 25 
  357.                 begin
  358.                 select @pos = @pos + 1
  359.                 select @substidx = 1
  360.                 end
  361.             else
  362.                 select @substidx = @substidx + 1
  363.             select @curchar = substring(@subschars, @substidx, 1)
  364.             select @saverr = @@error
  365.             if (@saverr <> 0)
  366.                 goto EXIT_LABEL
  367.             select @name_out = stuff(@name_out, @pos, 1, @curchar)
  368.             select @saverr = @@error
  369.             if (@saverr <> 0)
  370.                 goto EXIT_LABEL
  371.         end
  372.         return (0)
  373. EXIT_LABEL:
  374.     if (@saverr <> 0)
  375.         begin
  376.             RAISERROR(15001, 16, -1, 'sp_MSuniquetempname')
  377.             return (1)
  378.         end
  379.             
  380. GO
  381. exec dbo.sp_MS_marksystemobject sp_MSuniquetempname 
  382. go
  383.  
  384. raiserror('Creating procedure sp_MSuniquecolname', 0,1)
  385. GO
  386.  
  387. create procedure sp_MSuniquecolname
  388.     @table_name nvarchar(270),  -- this is a qualified_name         
  389.     @base_colname sysname, 
  390.     @unique_colname sysname output
  391. as
  392. begin
  393.     
  394.     set nocount on
  395.     
  396.     declare @icol_suffix int
  397.     
  398.     select @icol_suffix = ( max(colorder) + 1 ) from syscolumns 
  399.         where id = object_id( @table_name )
  400.  
  401.     select @unique_colname = @base_colname 
  402.  
  403.     while exists( 
  404.             select * from syscolumns 
  405.                 where id = object_id( @table_name ) 
  406.                   and name = @unique_colname
  407.     )
  408.     begin
  409.         select @unique_colname = @base_colname + convert( nvarchar(40), @icol_suffix )      
  410.         select @icol_suffix = @icol_suffix * ( @@spid + 1 )
  411.     end
  412.     
  413. end
  414. go
  415.  
  416. exec dbo.sp_MS_marksystemobject sp_MSuniquecolname
  417. go
  418.  
  419. raiserror('Creating procedure sp_MSaddguidcolumn', 0,1)
  420. GO
  421.  
  422. SET ANSI_NULLS ON 
  423. SET QUOTED_IDENTIFIER ON
  424. go
  425. create procedure sp_MSaddguidcolumn
  426.     @source_owner    sysname,
  427.     @source_table     sysname         /* table name */
  428. as
  429.     declare @rowguidcol         sysname
  430.     declare @id                    int
  431.     declare @qualified_name        nvarchar(270)
  432.     declare @columns            varbinary(128)
  433.     declare @retcode            int
  434.     declare @colid                int
  435.     declare @pubid                uniqueidentifier
  436.  
  437.     set nocount on
  438.  
  439.     -- Security check
  440.     if 1 <> is_member('db_owner') 
  441.     begin
  442.         raiserror(15247, 11, -1)
  443.         return (1)
  444.     end
  445.  
  446.     select @qualified_name = QUOTENAME(@source_owner) + '.' + QUOTENAME(@source_table)
  447.     select @id = object_id(@qualified_name)
  448.     
  449.     /* Alter the source table to add a rowguid column */
  450.     begin tran
  451.     save tran sp_MSaddguidcolumn
  452.     exec dbo.sp_MSunmarkreplinfo @source_table, @source_owner
  453.     if @@ERROR <>0 goto UNDO
  454.  
  455.     if not exists (select * from syscolumns
  456.         where ObjectProperty(object_id(@qualified_name), 'tablehasrowguidcol')=1)
  457.     begin
  458.         exec dbo.sp_MSuniquecolname @qualified_name, 'rowguid', @rowguidcol output
  459.         exec ('alter table ' + @qualified_name + ' add ' + @rowguidcol + ' uniqueidentifier ROWGUIDCOL default newid() not null')
  460.         if @@ERROR<>0 goto UNDO
  461.     end
  462.     exec dbo.sp_MSunmarkreplinfo @source_table, @source_owner, 1
  463.     if @@ERROR<>0 goto UNDO
  464.     
  465.     commit tran
  466.     return (0)
  467. UNDO:
  468.     rollback tran sp_MSaddguidcolumn
  469.     commit tran
  470.     return (1)    
  471. go
  472.  
  473. exec dbo.sp_MS_marksystemobject sp_MSaddguidcolumn 
  474. go
  475. grant exec on dbo.sp_MSaddguidcolumn to public
  476. go
  477. SET ANSI_NULLS OFF
  478. GO
  479. raiserror('Creating procedure sp_MSprepare_mergearticle', 0,1)
  480. GO
  481.  
  482. SET ANSI_NULLS ON 
  483. SET QUOTED_IDENTIFIER ON
  484. go
  485. create procedure sp_MSprepare_mergearticle
  486.     @source_owner    sysname,
  487.     @source_table     sysname,         /* table name */
  488.     @publication     sysname,
  489.     @qualified_tablename     nvarchar(270)
  490. as
  491.     declare @retcode int
  492.  
  493.     -- Security check
  494.     exec @retcode= dbo.sp_MSreplcheck_publish
  495.     if @@error <> 0 or @retcode <> 0 return (1)
  496.  
  497.     exec @retcode = sp_MSaddguidcolumn @source_owner, @source_table
  498.  
  499.     if @@error <> 0 or @retcode <> 0
  500.         return (1)
  501.  
  502.     exec @retcode = sp_MSaddguidindex @publication, @source_owner, @source_table
  503.  
  504.     if @@error <> 0 or @retcode <> 0
  505.         return (1)
  506.  
  507.     exec @retcode = sp_MSaddmergetriggers @qualified_tablename
  508.  
  509.     if @@error <> 0 or @retcode <> 0
  510.         return (1)
  511. go
  512.  
  513. exec dbo.sp_MS_marksystemobject sp_MSprepare_mergearticle 
  514. go
  515. grant exec on dbo.sp_MSprepare_mergearticle to public
  516. go
  517. SET ANSI_NULLS OFF
  518. GO
  519.  
  520. raiserror('Creating procedure sp_MSgetcolumnlist', 0,1)
  521. GO               
  522. create procedure sp_MSgetcolumnlist(
  523.     @pubid                uniqueidentifier,
  524.     @column_list         nvarchar(4000) OUTPUT,
  525.     @source_objid        int,
  526.     @guid_alias            sysname=NULL,
  527.     @phase                int=null, -- null=result in @column_list, non-null=result as resultset
  528.     @allcolsreturned    bit=null output -- mainly useful if result is in resultset
  529. )
  530. AS
  531.     /* 
  532.     ** if it is not vertically partitioned, then get all columns 
  533.     ** else get the column list as given in columns of sysmergearticles
  534.     */
  535.     declare @bitset        int
  536.     declare @columns    varbinary(125)
  537.     declare @setcolcnt    int
  538.     declare @colcnt        int
  539.     declare @colname    nvarchar(140)
  540.     declare @colid        int
  541.     declare @sourcename    sysname
  542.     declare @objname    sysname
  543.     declare @quoted_objname    nvarchar(140)
  544.     declare @qual_colname    nvarchar(140)
  545.     declare @coltab table(qual_colname nvarchar(300), id int identity(1,1))
  546.  
  547.     if @guid_alias is NULL
  548.     begin
  549.         select @objname=object_name(@source_objid)
  550.         select @quoted_objname = QUOTENAME(@objname)
  551.     end
  552.     else
  553.         select @quoted_objname=@guid_alias    
  554.  
  555.     select @columns = columns from sysmergearticles where objid = @source_objid and pubid=@pubid
  556.     select @column_list = ''
  557.     select @setcolcnt    = 0
  558.     select @colcnt = count(*) from syscolumns where id = @source_objid
  559.     declare collist CURSOR LOCAL FAST_FORWARD FOR 
  560.            select name, colid from syscolumns where id = @source_objid order by colid ASC
  561.     FOR READ ONLY
  562.  
  563.     open collist
  564.     fetch collist into @colname, @colid
  565.  
  566.     WHILE (@@fetch_status <> -1)
  567.     BEGIN
  568.         exec @bitset = sp_MStestbit @columns, @colid
  569.     --    if @bitset<>0
  570.         if @bitset<>0 or @columns is null or @columns = ''
  571.         begin
  572.             select @colname = QUOTENAME(@colname) --previously we use rowguidcol to replace 'rowguid'
  573.                                                   --which can cause problems and is not necessary.
  574.  
  575.             if @phase is null
  576.             begin
  577.                 if @column_list=''                      
  578.                     select @column_list = @quoted_objname + '.' + @colname
  579.                 else
  580.                     select @column_list = @column_list + ', ' + @quoted_objname + '.' + @colname    
  581.             end
  582.             else
  583.             begin
  584.                 if 0 = @setcolcnt
  585.                 begin
  586.                     set @qual_colname= @quoted_objname + '.' + @colname
  587.                     insert into @coltab(qual_colname) values (@qual_colname)
  588.                 end
  589.                 else
  590.                 begin
  591.                     set @qual_colname= ',' + @quoted_objname + '.' + @colname
  592.                     insert into @coltab(qual_colname) values (@qual_colname)
  593.                 end
  594.             end
  595.  
  596.             select @setcolcnt = @setcolcnt + 1
  597.         end                    
  598.     fetch next from collist into @colname, @colid            
  599.     END
  600.  
  601.     close collist
  602.     deallocate collist
  603.  
  604.     if @phase is null
  605.     begin
  606.         if @setcolcnt = @colcnt
  607.         begin
  608.             set @allcolsreturned= 1
  609.             select @column_list = ' * '
  610.         end
  611.         else
  612.         begin
  613.             set @allcolsreturned= 0
  614.         end
  615.     end
  616.     else
  617.     begin
  618.         if @setcolcnt = @colcnt
  619.         begin
  620.             set @allcolsreturned= 1
  621.             select @phase, @quoted_objname + '.*'
  622.         end
  623.         else
  624.         begin
  625.             set @allcolsreturned= 0
  626.             select @phase, qual_colname from @coltab order by id
  627.         end
  628.     end
  629. GO
  630. exec dbo.sp_MS_marksystemobject sp_MSgetcolumnlist 
  631. go
  632.  
  633.  
  634. raiserror('Creating procedure sp_MSaddguidindex', 0,1)
  635. GO
  636.  
  637. SET ANSI_NULLS ON 
  638. SET QUOTED_IDENTIFIER ON
  639. go
  640. create procedure sp_MSaddguidindex
  641.     @publication     sysname,
  642.     @source_owner    sysname,
  643.     @source_table     sysname        
  644. as
  645.     set nocount on
  646.     declare @indexname     nvarchar(270)
  647.     declare @colname    nvarchar(270)
  648.     declare @retcode int
  649.     declare @qualified_name nvarchar(270)
  650.     declare @colid        int
  651.     declare @columns    varbinary(125)
  652.     declare @id            int
  653.     declare @pubid        uniqueidentifier
  654.       declare @mergepublish    int
  655.  
  656.     -- Security check
  657.     exec @retcode = dbo.sp_MSreplcheck_publish
  658.     if @@error <> 0 or @retcode <> 0 return (1)
  659.  
  660.       select @mergepublish = 0x4000
  661.       
  662.     select @pubid = pubid from sysmergepublications 
  663.         where name=@publication and publisher=@@SERVERNAME and publisher_db=db_name()
  664.     select @qualified_name = QUOTENAME(@source_owner) + '.' + QUOTENAME(@source_table)
  665.     select @id = object_id(@qualified_name)
  666.  
  667.     select @colid=colid from syscolumns where id=@id and columnproperty(@id, name, 'isrowguidcol')=1
  668.     update syscolumns set colstat=colstat | @mergepublish where id=@id and colid=@colid
  669.     if @@ERROR<>0
  670.         return (1)
  671.  
  672.     /* Update the columns bitmaps in all articles at the current publisher that share the same table */
  673.     declare artpubs CURSOR LOCAL FAST_FORWARD FOR 
  674.         select DISTINCT pubid from sysmergearticles where objid=@id and pubid
  675.             in ( select pubid from sysmergepublications where UPPER(publisher) = UPPER(@@SERVERNAME) 
  676.                 and publisher_db = db_name())
  677.     FOR READ ONLY
  678.     open artpubs
  679.     fetch next from artpubs into @pubid
  680.      
  681.     while (@@fetch_status <> -1)
  682.         begin
  683.             select @columns=columns from sysmergearticles where objid=@id and pubid=@pubid
  684.             exec @retcode = sp_MSsetbit @columns OUTPUT, @colid
  685.             if @retcode<>0 or @@ERROR<>0
  686.                 return (1)
  687.             update sysmergearticles set columns=@columns where objid=@id and pubid = @pubid
  688.             if @@ERROR<>0
  689.                 return (1)
  690.             fetch next from artpubs into @pubid
  691.         end 
  692.     close artpubs
  693.     deallocate artpubs
  694.  
  695.    
  696.     select @indexname = 'index_' + convert(nvarchar(36), @id)
  697.  
  698.     /* Make sure index name is unique */
  699.     exec @retcode = dbo.sp_MSuniqueobjectname @indexname, @indexname output
  700.     if @retcode <>0 return (1)
  701.  
  702.     select @colname=name from syscolumns where id=@id and columnproperty(@id, name, 'isrowguidcol')=1
  703.     if (@colname is null)
  704.         return (1)
  705.     
  706.     /* Alter the source table to add a rowguid column index */
  707.     if (not exists (select * from sysindexes
  708.         where id = object_id(@qualified_name) and
  709.             @colname = index_col(@qualified_name, indid, 1)
  710.             and indexproperty(id, name, 'IsUnique') = 1 and 
  711.             index_col(@qualified_name, indid, 2) is null))
  712.     begin
  713.         declare @quoted_rgcol nvarchar(290)
  714.         set @quoted_rgcol= quotename(@colname)
  715.         exec ('create unique index ' + @indexname  + ' on ' + @qualified_name + '(' +  @quoted_rgcol + ')')
  716.         if @@ERROR <>0 return (1) 
  717.     end
  718.     return (0)
  719. go
  720.  
  721.  
  722. exec dbo.sp_MS_marksystemobject sp_MSaddguidindex
  723. go
  724. grant exec on dbo.sp_MSaddguidindex to public
  725. go
  726. SET ANSI_NULLS OFF
  727.  
  728. raiserror('Creating procedure sp_MSrefcnt', 0,1)
  729. GO
  730.  
  731. create procedure sp_MSrefcnt
  732.     @objid int, @refcnt int output
  733. as
  734.     set @refcnt = 0
  735.     create table #temprefs (objid int NOT NULL)
  736.     insert into #temprefs select distinct rkeyid from sysreferences where fkeyid = @objid
  737.  
  738.     while (@@rowcount > 0)
  739.         insert into #temprefs select distinct rkeyid from
  740.             sysreferences where fkeyid in (select objid from #temprefs) and
  741.                 rkeyid not in (select objid from #temprefs)
  742.  
  743.     select @refcnt = count(*) from #temprefs
  744.     return (0)
  745. GO
  746.  
  747. exec dbo.sp_MS_marksystemobject sp_MSrefcnt
  748. go
  749.  
  750.  
  751. raiserror('Creating procedure sp_MSgentablenickname', 0,1)
  752. GO
  753.  
  754. create procedure sp_MSgentablenickname
  755.             @tablenick    int    output, @nickname int, @objid int
  756. as
  757.  
  758.     declare @refcnt int
  759.     declare @retval int
  760.     
  761.     /* Create a tablenickname from the following formula
  762.     **        1.  Get the refcnt, use it for the high order digits so
  763.     **            that processing inserts by ascending tablenickname works well
  764.     **             and processing deletes by descending tablenickname works well.
  765.     **        2.  Use a couple of digits from the nickname so that it is less likely
  766.     **            to collide with tablenickname generated at another merge publisher.
  767.     **        3.  Increment as necessary to make it unique within the publication and database.
  768.     */
  769.     exec @retval = dbo.sp_MSrefcnt @objid, @refcnt output
  770.     if @retval <> 0 return (1)
  771.  
  772.     if @nickname < 0
  773.         set @nickname = 0 - @nickname
  774.  
  775.     /* the biggest value for int is 2147483647, we therefore use another algorithm when
  776.     ** @refcnt is bigger than 200
  777.     */
  778.     if @refcnt < 200
  779.     begin
  780.         set @tablenick = 1000 * ((@refcnt * 10000) + (@nickname % 10000))
  781.         while exists (select * from sysmergearticles where nickname = @tablenick)
  782.             set @tablenick = @tablenick + 1
  783.     end
  784.     else
  785.         select @tablenick=max(nickname) + 1 from sysmergearticles
  786.     return (0)
  787. go
  788.  
  789. exec dbo.sp_MS_marksystemobject sp_MSgentablenickname
  790. go
  791.  
  792. raiserror('Creating procedure sp_MStablenickname', 0,1)
  793. GO
  794.  
  795. create procedure sp_MStablenickname 
  796.     @owner        sysname,
  797.     @tablename     sysname,
  798.     @nick int     output
  799. as
  800.     declare @qualified_name nvarchar(270)
  801.     if @owner is not null
  802.         select @qualified_name = QUOTENAME(@owner) + '.' + QUOTENAME(@tablename)
  803.     else 
  804.         select @qualified_name = QUOTENAME(@tablename)
  805.         
  806.     select @nick = nickname from sysmergearticles a, sysobjects o
  807.             where a.objid = o.id and o.id = OBJECT_ID(@qualified_name) and
  808.                 (user_name(uid) = @owner or @owner is null)
  809.     if @nick is NULL return (1)             
  810.     return (0)
  811. go
  812.  
  813. exec dbo.sp_MS_marksystemobject sp_MStablenickname 
  814. go
  815.  
  816. raiserror('Creating procedure sp_MStablenamefromnick', 0,1)
  817. GO
  818.  
  819. create procedure sp_MStablenamefromnick
  820.     @nick int,
  821.     @tablename nvarchar(270) output,
  822.     @pubid uniqueidentifier = NULL
  823. as
  824.     declare @owner sysname
  825.     declare @table sysname
  826.     if (@pubid is null)
  827.         select @table = name, @owner = user_name(uid) from sysobjects where id in (select 
  828.             objid from sysmergearticles where nickname = @nick)
  829.     else
  830.         select @table = name, @owner = user_name(uid) from sysobjects where id in (select 
  831.             objid from sysmergearticles where nickname = @nick and pubid = @pubid)
  832.             
  833.     select @tablename = QUOTENAME(@owner) + '.' + QUOTENAME(@table)
  834.     if (@table is NULL) or (@owner is NULL) 
  835.     begin
  836.         raiserror(21124, 16, -1, @nick)
  837.         return (1) 
  838.     end
  839.     return (0)
  840. go
  841.  
  842. exec dbo.sp_MS_marksystemobject sp_MStablenamefromnick
  843. go
  844.  
  845.  
  846. raiserror('Creating procedure sp_MSgetmakegenerationapplock', 0,1)
  847. GO
  848.  
  849. create procedure sp_MSgetmakegenerationapplock
  850.     @head_of_queue int OUTPUT
  851.     as
  852.     set nocount on
  853.  
  854.     -- Security check
  855.     if not exists (select * from dbo.sysmergepublications 
  856.                         where 1 = {fn ISPALUSER(pubid)})
  857.     begin
  858.         RAISERROR (15247, 11, -1)
  859.         return (1)
  860.     end
  861.  
  862.     declare @retcode smallint
  863.        declare @lock_resource nvarchar(255)
  864.  
  865.        select @retcode = 0
  866.     select @head_of_queue = 0
  867.     
  868.     select @lock_resource = N'MSinternal_makegeneration_inprogress' + 
  869.                 convert(nvarchar(11), db_id())
  870.  
  871.     
  872.     -- If someone else is making generations / has just made one, exit so
  873.     -- that we won't deadlock
  874.     exec @retcode = sp_getapplock @Resource = @lock_resource,
  875.                                   @LockMode = N'Exclusive',
  876.                                   @LockOwner = N'Session',
  877.                                   @LockTimeout = 0 -- do not wait at all. 
  878.  
  879.     if @@error <> 0 or @retcode < 0
  880.     begin
  881.         -- If the previous applock request timed out, then try again, this time using the default timeout.
  882.         -- Note that even though the -1 lock timeout means indefinite timeout, the query timeout set on the 
  883.         -- session overrides the lock timeout. So it's okay even if the default @@lock_timeout is -1.
  884.         if (@retcode = -1)
  885.         begin
  886.             exec @retcode = sp_getapplock @Resource = @lock_resource,
  887.                         @LockMode = N'Exclusive',
  888.                         @LockOwner = N'Session'
  889.             -- If we succeeded to get the lock, set @lock_acquired to 1 so that the exit code releases the lock.
  890.             if (@retcode >= 0)
  891.             begin
  892.                 goto EXIT_PROC
  893.             end
  894.         end
  895.     end
  896.     else
  897.     begin
  898.         select @head_of_queue = 1
  899.     end
  900.  
  901. EXIT_PROC:
  902.     return @retcode
  903.  
  904. go
  905.  
  906. exec dbo.sp_MS_marksystemobject sp_MSgetmakegenerationapplock 
  907. go
  908. grant exec on dbo.sp_MSgetmakegenerationapplock to public
  909. go
  910.  
  911.  
  912. raiserror('Creating procedure sp_MSreleasemakegenerationapplock', 0,1)
  913. GO
  914.  
  915. create procedure sp_MSreleasemakegenerationapplock
  916.     as
  917.     set nocount on
  918.  
  919.     -- Security check
  920.     if not exists (select * from dbo.sysmergepublications 
  921.                         where 1 = {fn ISPALUSER(pubid)})
  922.     begin    
  923.         RAISERROR (15247, 11, -1)
  924.         return (1)
  925.     end
  926.  
  927.     declare @retcode smallint
  928.        declare @lock_resource nvarchar(255)
  929.  
  930.        select @retcode = 0
  931.     select @lock_resource = N'MSinternal_makegeneration_inprogress' + 
  932.                 convert(nvarchar(11), db_id())
  933.  
  934.        exec @retcode = sp_releaseapplock @Resource = @lock_resource, @LockOwner = N'Session'
  935.        if @@error <> 0 or @retcode < 0
  936.         return (1)    
  937.     else
  938.         return (0)
  939.                 
  940. go
  941. exec dbo.sp_MS_marksystemobject sp_MSreleasemakegenerationapplock 
  942. go
  943. grant exec on dbo.sp_MSreleasemakegenerationapplock to public
  944. go
  945.  
  946.  
  947. raiserror('Creating procedure sp_MSmakegeneration', 0,1)
  948. GO
  949. create procedure sp_MSmakegeneration
  950.     @gencheck int = 0
  951.     as
  952.     set nocount on
  953.  
  954.     declare @gen int
  955.     declare @nick int
  956.     declare @genguid uniqueidentifier
  957.     declare @dt datetime
  958.     declare @dt2 datetime
  959.     declare @art_nick int
  960.     declare @first_ts int
  961.     declare @makenewrow bit
  962.     declare @retcode smallint
  963.     declare @guidnull uniqueidentifier
  964.     declare @nickbin varbinary(255)
  965.     declare @maxgendiff_fornewrow int
  966.     declare @count_of_articles int
  967.     declare @lock_acquired bit
  968.        declare @lock_resource nvarchar(255)
  969.     declare @procfailed bit
  970.     declare @delete_old_genhistory bit
  971.     declare @close_old_genhistory bit
  972.     declare @localize_zeroartnick_generations bit
  973.         
  974.     -- Security check
  975.     if not exists (select * from dbo.sysmergepublications where 1 = {fn ISPALUSER(pubid)})
  976.     begin    
  977.         RAISERROR (15247, 11, -1)
  978.         return (1)
  979.     end
  980.  
  981.     select @procfailed = 1
  982.        select @retcode = 0
  983.  
  984.     set @guidnull = '00000000-0000-0000-0000-000000000000'
  985.     
  986.     set @genguid = newid()
  987.     exec @retcode=sp_MSgetreplnick @nickname = @nick out
  988.     if @retcode<>0 or @@error<>0 goto EXIT_PROC
  989.  
  990.     -- convert @nick into binary and add a guard byte if needed
  991.     if @nick % 256 = 0
  992.         set @nickbin = convert(binary(4), @nick) + 0x01
  993.     else
  994.         set @nickbin = convert(binary(4), @nick)
  995.  
  996.     select @dt2 = max(coldate) from dbo.MSmerge_genhistory (NOLOCK) where guidsrc = guidlocal
  997.     set @dt = getdate()
  998.  
  999.     if datediff(dd, @dt2, @dt) = 0
  1000.     begin
  1001.         if 500 > datediff(ms, @dt2, @dt) and 0 < datediff(ms, @dt2, @dt)
  1002.         begin
  1003.             select @procfailed = 0
  1004.             goto EXIT_PROC
  1005.         end
  1006.     end
  1007.  
  1008.     if @gencheck = 3
  1009.         set @localize_zeroartnick_generations = 1
  1010.     else
  1011.         set @localize_zeroartnick_generations = 0
  1012.  
  1013.     -- localize interrupted generations
  1014.     exec @retcode= sp_MSlocalizeinterruptedgenerations @localize_zeroartnick_generations = @localize_zeroartnick_generations
  1015.     if @retcode<>0 or @@error<>0 goto EXIT_PROC
  1016.  
  1017.     -- If @gencheck param is set to 1 ( = ForceConvergence), look for rows with missing generation numbers and set their
  1018.     -- gen to 0
  1019.     if @gencheck = 1 or @gencheck = 2
  1020.     begin
  1021.         update dbo.MSmerge_contents set generation = 0 where generation not in
  1022.             (select generation from dbo.MSmerge_genhistory)
  1023.         update dbo.MSmerge_tombstone set generation = 0 where generation not in
  1024.             (select generation from dbo.MSmerge_genhistory)
  1025.     end
  1026.     /*
  1027.     ** If there are no zero generation tombstones or rows, add a dummy row in there. 
  1028.     */
  1029.        if not exists (select * from dbo.MSmerge_genhistory)
  1030.     begin
  1031.            insert into dbo.MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) values
  1032.             (@genguid, @genguid, 1, 0, @nickbin, @dt)
  1033.         if (@@error <> 0) goto EXIT_PROC
  1034.     end
  1035.  
  1036.     select @art_nick = min(nickname), @count_of_articles = count(*) from sysmergearticles
  1037.  
  1038.     -- Calculate how much less than the max generation in MSmerge_genhistory are we willing to have the minimum open generation in MSmerge_genhistory.
  1039.     -- Having a number smaller than or roughly equal to the number of articles will cause more aggressive closing of existing open gens (and making new rows) with 0 changes
  1040.     -- and hence more generations for merge agents to deal with. Having a very high number will cause less aggressive closing of open gens but will cause the
  1041.     -- common gens of replicas to be stuck at lower numbers because of the existence of "holes" at much lower gen values. An optimization that works well
  1042.     -- and is a compromise between the two extremes is to have the max of 100 or (2 * @count_of_articles) + 1 as the max diff we allow before deciding to make a new row.
  1043.     if ((2 * @count_of_articles) + 1) > 100
  1044.         select @maxgendiff_fornewrow = (2 * @count_of_articles) + 1
  1045.     else
  1046.         select @maxgendiff_fornewrow = 100
  1047.  
  1048.     while @art_nick is not null
  1049.     begin
  1050.         declare @cmd nvarchar(200)
  1051.         declare @old_bi_gen int
  1052.         declare @bi_objid int
  1053.  
  1054.         set @old_bi_gen= NULL -- if @old_bi_gen stays NULL: no need to move bi-rows
  1055.         set @bi_objid= NULL
  1056.         set @delete_old_genhistory = 0
  1057.         set @close_old_genhistory = 0
  1058.         set @makenewrow = 0
  1059.         
  1060.         set @bi_objid= (select top 1 before_image_objid from sysmergearticles where nickname = @art_nick)
  1061.         if @bi_objid is not null
  1062.         begin
  1063.             set @cmd= 'update dbo.' + quotename(object_name(@bi_objid)) + ' set generation= @gen where generation = @oldgen'
  1064.         end
  1065.         
  1066.         begin tran
  1067.         save tran sp_MSmakegeneration
  1068.         select @gen = max(gen_cur) from sysmergearticles (updlock holdlock) where nickname = @art_nick and gen_cur is not null
  1069.  
  1070.         -- if either we have no gen_cur set yet, or if we have one but no corresponding genhistory row or we have a closed one which
  1071.         -- was bcp-ed in after a reinit, we need to create a new one.
  1072.         if @gen is null or 
  1073.             (    @gen is not null 
  1074.                 and not exists (select generation from dbo.MSmerge_genhistory where generation = @gen and guidlocal = @guidnull)
  1075.             )
  1076.         begin
  1077.             declare @oldgen int
  1078.             declare @maxgencur int
  1079.  
  1080.             set @genguid = newid()
  1081.             set @oldgen = @gen
  1082.  
  1083.             select @gen = COALESCE(1 + max(generation), 1) from dbo.MSmerge_genhistory (updlock)
  1084.             
  1085.             -- Make sure that the new generation value is not smaller than any existing sysmergearticles.gen_cur.
  1086.             select @maxgencur = isnull(max(gen_cur),0) from sysmergearticles where gen_cur is not null
  1087.  
  1088.             if (@gen <= @maxgencur)
  1089.             begin
  1090.                 set @gen = @maxgencur + 1
  1091.                 -- Now we are guaranteed to not collide with an existing gen_cur
  1092.             end
  1093.             
  1094.             insert into dbo.MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) 
  1095.                 values(@genguid, @guidnull, @gen, @art_nick, @nickbin, @dt)
  1096.             if (@@error <> 0)
  1097.             begin
  1098.                 goto EXIT_RELEASE_TRAN
  1099.             end    
  1100.             
  1101.             update sysmergearticles set gen_cur = @gen where nickname = @art_nick
  1102.             if (@@error <> 0)
  1103.             begin
  1104.                 goto EXIT_RELEASE_TRAN
  1105.             end    
  1106.  
  1107.             -- if this was the case of a gen_cur with no matching genhistory rows, then update the contents and tombstones rows with the new generation value.
  1108.             if @oldgen is not null
  1109.             begin
  1110.                 update dbo.MSmerge_contents set generation = @gen, partchangegen = @gen, joinchangegen = @gen
  1111.                      where generation = @oldgen and partchangegen = @oldgen and tablenick = @art_nick
  1112.                 if (@@error <> 0)
  1113.                 begin
  1114.                     goto EXIT_RELEASE_TRAN
  1115.                 end    
  1116.                 update dbo.MSmerge_contents set generation = @gen, joinchangegen = @gen
  1117.                      where generation = @oldgen and joinchangegen = @oldgen and tablenick = @art_nick
  1118.                 if (@@error <> 0)
  1119.                 begin
  1120.                     goto EXIT_RELEASE_TRAN
  1121.                 end    
  1122.                 update dbo.MSmerge_contents set generation = @gen where generation = @oldgen and tablenick = @art_nick
  1123.                 if (@@error <> 0)
  1124.                 begin
  1125.                     goto EXIT_RELEASE_TRAN
  1126.                 end
  1127.                 update dbo.MSmerge_tombstone set generation = @gen where generation = @oldgen and tablenick = @art_nick
  1128.                 if (@@error <> 0)
  1129.                 begin
  1130.                     goto EXIT_RELEASE_TRAN
  1131.                 end
  1132.  
  1133.                 if @bi_objid is not null
  1134.                 begin
  1135.                     exec dbo.sp_executesql @cmd, N'@gen int, @oldgen int', @gen= @gen, @oldgen= @oldgen
  1136.                     if @@ERROR <> 0 goto EXIT_RELEASE_TRAN
  1137.                 end
  1138.             end
  1139.         end
  1140.             
  1141.         -- these updates should be hitting zero rows...
  1142.         if exists (select * from dbo.MSmerge_contents (readpast readcommitted) where generation = 0 and tablenick = @art_nick)
  1143.         begin
  1144.             update dbo.MSmerge_contents set generation = @gen, partchangegen = @gen, joinchangegen = @gen
  1145.                  where generation = 0 and partchangegen = 0 and tablenick = @art_nick
  1146.             if (@@error <> 0)
  1147.             begin
  1148.                 goto EXIT_RELEASE_TRAN
  1149.             end    
  1150.             update dbo.MSmerge_contents set generation = @gen, joinchangegen = @gen
  1151.                  where generation = 0 and joinchangegen = 0 and tablenick = @art_nick
  1152.             if (@@error <> 0)
  1153.             begin
  1154.                 goto EXIT_RELEASE_TRAN
  1155.             end    
  1156.             update dbo.MSmerge_contents set generation = @gen where generation = 0 and tablenick = @art_nick
  1157.             if (@@error <> 0)
  1158.             begin
  1159.                 goto EXIT_RELEASE_TRAN
  1160.             end
  1161.         end
  1162.             
  1163.         if exists (select * from dbo.MSmerge_tombstone (readpast readcommitted) where generation = 0 and tablenick = @art_nick)
  1164.         begin
  1165.             update dbo.MSmerge_tombstone set generation = @gen where generation = 0 and tablenick = @art_nick
  1166.             if (@@error <> 0)
  1167.             begin
  1168.                 goto EXIT_RELEASE_TRAN
  1169.             end
  1170.         end
  1171.         if not exists (select * from dbo.MSmerge_contents where tablenick = @art_nick and
  1172.                         generation = @gen) and
  1173.            not exists (select * from dbo.MSmerge_tombstone where tablenick = @art_nick and
  1174.                         generation = @gen)
  1175.         begin
  1176.  
  1177.             select @dt2 = coldate from dbo.MSmerge_genhistory where generation = @gen
  1178.             if datediff(dd, @dt2, @dt) = 0 and not exists (select * from dbo.MSmerge_genhistory
  1179.                     where generation > @maxgendiff_fornewrow + @gen)
  1180.             begin
  1181.                 set @makenewrow = 0
  1182.                 set @delete_old_genhistory = 0
  1183.                 
  1184.                 -- If @gencheck param is set to 3 (= OverrideMakeNewGenerations), set the @makenewrow flag
  1185.                 -- This is done for message based merges to ensure that the incomplete gens always get closed
  1186.                 -- during every merge if there are completed generations > than this one.
  1187.                 -- Besides closed generations > this one, we also need to watch out for open generations > this one
  1188.                 -- that have pending changes, and hence sp_MSmakegeneration will eventually close them out. This is
  1189.                 -- required when the @gen just happens to be processed before other open generations with changes.
  1190.                 if @gencheck = 3 
  1191.                 begin
  1192.                     if exists (select * from dbo.MSmerge_genhistory gh 
  1193.                                 where gh.generation > @gen 
  1194.                                 and gh.guidlocal <> @guidnull)
  1195.                         or exists (select * from dbo.MSmerge_contents mc where mc.generation > @gen)
  1196.                         or exists (select * from dbo.MSmerge_tombstone mt where mt.generation > @gen)
  1197.                     begin
  1198.                         set @makenewrow = 1
  1199.                         set @old_bi_gen= @gen -- we will move bi-rows
  1200.                         set @delete_old_genhistory = 1
  1201.                     end
  1202.                 end                
  1203.             end
  1204.             else
  1205.             begin
  1206.                 set @makenewrow = 1
  1207.                 set @old_bi_gen= @gen -- we will move bi-rows
  1208.                 set @delete_old_genhistory = 1
  1209.             end
  1210.         end
  1211.         else
  1212.         begin
  1213.             set @makenewrow = 1
  1214.             set @delete_old_genhistory = 0    -- don't delete existing genhistory row. just mark it as closed.
  1215.             set @close_old_genhistory = 1
  1216.         end
  1217.  
  1218.         if (@makenewrow = 1)
  1219.         begin
  1220.             declare @newgen int
  1221.  
  1222.             /* reset next generation for this article */
  1223.             set @genguid = newid()
  1224.             insert into dbo.MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) 
  1225.                 select @genguid, @guidnull, COALESCE(1 + max(generation), 1), @art_nick, @nickbin, @dt from dbo.MSmerge_genhistory (updlock)
  1226.             if (@@error <> 0)
  1227.             begin
  1228.                 goto EXIT_RELEASE_TRAN
  1229.             end    
  1230.             select @newgen  =  generation  from dbo.MSmerge_genhistory where guidsrc = @genguid
  1231.             update sysmergearticles set gen_cur = @newgen where nickname = @art_nick
  1232.             if (@@error <> 0)
  1233.             begin
  1234.                 goto EXIT_RELEASE_TRAN
  1235.             end    
  1236.  
  1237.             if @bi_objid is not null and @old_bi_gen is not NULL
  1238.             begin
  1239.                 exec dbo.sp_executesql @cmd, N'@gen int, @oldgen int', @gen = @newgen, @oldgen = @old_bi_gen
  1240.                 if @@ERROR <> 0 goto EXIT_RELEASE_TRAN
  1241.             end
  1242.         end
  1243.  
  1244.         if (@delete_old_genhistory = 1)
  1245.         begin
  1246.             declare @error int
  1247.             declare @genhistory_rowsdeleted int
  1248.  
  1249.             -- delete the old genhistory row only if there still aren't any rows in contents or 
  1250.             -- tombstone with this generation value. Note that after the previous update statement on sysmergearticles
  1251.             -- no new spids can take locks on sysmergearticles and hence cannot 
  1252.             -- insert any new rows with the old gen_cur.
  1253.             delete from dbo.MSmerge_genhistory 
  1254.             where generation = @gen
  1255.             and not exists (select * from dbo.MSmerge_contents where tablenick = @art_nick and generation = @gen) 
  1256.             and not exists (select * from dbo.MSmerge_tombstone where tablenick = @art_nick and generation = @gen)
  1257.  
  1258.             select @genhistory_rowsdeleted = @@rowcount, @error = @@error
  1259.  
  1260.             -- If the genhistory row which we previously thought could be deleted, now has changes in contents or 
  1261.             -- tombstone, it's okay to not delete it and still leave it as open. In future this open generation
  1262.             -- will be treated as an interrupted generation and the changes in it will be moved to a new local 
  1263.             -- generation. So there will be convergence. Deleting the genhistory row based on incorrect past determination
  1264.             -- of 0 changes is dangerous and can easily cause non-convergence.
  1265.             -- The best solution is to close this generation if we finally didn't delete it. The reason is that it
  1266.             -- allows subscribers to move their last received watermark higher than this open generation.
  1267.             if @genhistory_rowsdeleted = 0
  1268.             begin
  1269.                 set @close_old_genhistory = 1
  1270.             end
  1271.  
  1272.             if (@error <> 0)
  1273.             begin
  1274.                 goto EXIT_RELEASE_TRAN
  1275.             end    
  1276.         end
  1277.  
  1278.         if (@close_old_genhistory = 1)
  1279.         begin
  1280.             set @genguid = newid()
  1281.             update dbo.MSmerge_genhistory set guidsrc = @genguid, guidlocal = @genguid, coldate = @dt
  1282.                 where generation = @gen
  1283.             if (@@error <> 0)
  1284.             begin
  1285.                 goto EXIT_RELEASE_TRAN
  1286.             end    
  1287.             update MSmerge_replinfo set recgen = @gen, recguid = @genguid, 
  1288.                 sentgen = @gen, sentguid = @genguid where replnickname = @nick
  1289.             if (@@error <> 0)
  1290.             begin
  1291.                 goto EXIT_RELEASE_TRAN
  1292.             end    
  1293.         end
  1294.  
  1295.         commit transaction        
  1296.  
  1297.         -- set up for next time through the loop
  1298.         select @art_nick = min(nickname) from sysmergearticles where nickname > @art_nick
  1299.         
  1300.         set @dt = getdate()
  1301.     end
  1302.  
  1303.     select @procfailed = 0
  1304.         
  1305. EXIT_RELEASE_TRAN:
  1306.  
  1307.     if (@procfailed = 1)
  1308.     begin
  1309.         rollback tran sp_MSmakegeneration
  1310.         commit transaction
  1311.     end
  1312.  
  1313. EXIT_PROC:
  1314.  
  1315.     if (@procfailed = 1)
  1316.         return (1)    
  1317.     else
  1318.         return (0)
  1319. go
  1320.  
  1321. exec dbo.sp_MS_marksystemobject sp_MSmakegeneration 
  1322. go
  1323. grant exec on dbo.sp_MSmakegeneration to public
  1324. go
  1325.  
  1326. raiserror('Creating procedure sp_MSfixlineageversions', 0,1)
  1327. GO
  1328.  
  1329. create procedure sp_MSfixlineageversions
  1330. as
  1331.     -- Security check
  1332.     if not exists (select * from dbo.sysmergepublications where 1 = {fn ISPALUSER(pubid)})
  1333.     begin    
  1334.         RAISERROR (15247, 11, -1)
  1335.         return (1)
  1336.     end
  1337.  
  1338.     declare @lNick int -- length of nickname in bytes
  1339.     declare @lVer int -- length of version in bytes
  1340.     declare @lEntry int -- length of entry in bytes
  1341.     declare @cEntries int
  1342.     declare @idx int -- @idx is the index of the entry that potentially needs to be bumped up
  1343.     set @lNick= 4
  1344.     set @lVer= 4
  1345.     set @lEntry= @lNick + @lVer
  1346.     set @cEntries= 31 -- max number of entries        
  1347.  
  1348.     if exists (select * from sysobjects where type = 'U' and name = 'MSmerge_contents')
  1349.     begin
  1350.         -- starting at the end of the lineage, replace every lower version by the following higher version
  1351.         set @idx= @cEntries - 2    -- lineage entries range from 0..30; compare 30 with 29, then 29 with 28, ..., 1 with 0
  1352.         while @idx >= 0
  1353.         begin
  1354.             update dbo.MSmerge_contents set lineage= 
  1355.                 -- leave everything before "entry[@idx].version" unmodified
  1356.                 substring(lineage, 1, @idx * @lEntry + @lNick) + 
  1357.                 -- replace "entry[@idx].version" by "entry[@idx+1].version"
  1358.                 substring(lineage, (@idx + 1) * @lEntry + @lNick + 1, @lVer) +    
  1359.                 -- leave everything starting at "entry[@idx+1].nickname" unmodified
  1360.                 substring(lineage, (@idx + 1) * @lEntry + 1, (@cEntries * @lEntry) - ((@idx + 1) * @lEntry) + 1) -- '+1' is for trailing byte
  1361.                 where
  1362.                     -- skip this step right away for shorter lineages
  1363.                     datalength(lineage) >= @lEntry * (@idx + 2)
  1364.                     and
  1365.                     (
  1366.                         -- either least significant version byte at second entry is higher, the other three are equal
  1367.                         (substring(lineage, (@idx + 1) * @lEntry + @lNick + 1, 1) > substring(lineage, @idx * @lEntry + @lNick + 1, 1) and
  1368.                             substring(lineage, (@idx + 1) * @lEntry + @lNick + 2, 3) = substring(lineage, @idx * @lEntry + @lNick + 2, 3))
  1369.                         or
  1370.                         -- 2nd least significant version byte at second entry is higher, the most and 2nd most significant bytes are equal
  1371.                         (substring(lineage, (@idx + 1) * @lEntry + @lNick + 2, 1) > substring(lineage, @idx * @lEntry + @lNick + 2, 1) and
  1372.                             substring(lineage, (@idx + 1) * @lEntry + @lNick + 3, 2) = substring(lineage, @idx * @lEntry + @lNick + 3, 2))
  1373.                         or
  1374.                         -- 3rd least significant version byte at second entry is higher, the most significant byte is equal
  1375.                         (substring(lineage, (@idx + 1) * @lEntry + @lNick + 3, 1) > substring(lineage, @idx * @lEntry + @lNick + 3, 1) and
  1376.                             substring(lineage, (@idx + 1) * @lEntry + @lNick + 4, 1) = substring(lineage, @idx * @lEntry + @lNick + 4, 1))
  1377.                         or
  1378.                         -- most significant byte at second entry is higher
  1379.                         substring(lineage, (@idx + 1) * @lEntry + @lNick + 4, 1) > substring(lineage, @idx * @lEntry + @lNick + 4, 1)
  1380.                     )
  1381.  
  1382.             if @@error<>0
  1383.             begin
  1384.                 return (1)
  1385.             end
  1386.  
  1387.             set @idx= @idx - 1
  1388.         end
  1389.     end
  1390.     if exists (select * from sysobjects where type = 'U' and name = 'MSmerge_tombstone')
  1391.     begin
  1392.         -- starting at the end of the lineage, replace every lower version by the following higher version
  1393.         set @idx= @cEntries - 2    -- lineage entries range from 0..30; compare 30 with 29, then 29 with 28, ..., 1 with 0
  1394.         while @idx >= 0
  1395.         begin
  1396.             update dbo.MSmerge_tombstone set lineage= 
  1397.                 -- leave everything before "entry[@idx].version" unmodified
  1398.                 substring(lineage, 1, @idx * @lEntry + @lNick) + 
  1399.                 -- replace "entry[@idx].version" by "entry[@idx+1].version"
  1400.                 substring(lineage, (@idx + 1) * @lEntry + @lNick + 1, @lVer) +    
  1401.                 -- leave everything starting at "entry[@idx+1].nickname" unmodified
  1402.                 substring(lineage, (@idx + 1) * @lEntry + 1, (@cEntries * @lEntry) - ((@idx + 1) * @lEntry) + 1) -- '+1' is for trailing byte
  1403.                 where
  1404.                     -- skip this step right away for shorter lineages
  1405.                     datalength(lineage) >= @lEntry * (@idx + 2)
  1406.                     and
  1407.                     (
  1408.                         -- either least significant version byte at second entry is higher, the other three are equal
  1409.                         (substring(lineage, (@idx + 1) * @lEntry + @lNick + 1, 1) > substring(lineage, @idx * @lEntry + @lNick + 1, 1) and
  1410.                             substring(lineage, (@idx + 1) * @lEntry + @lNick + 2, 3) = substring(lineage, @idx * @lEntry + @lNick + 2, 3))
  1411.                         or
  1412.                         -- 2nd least significant version byte at second entry is higher, the most and 2nd most significant bytes are equal
  1413.                         (substring(lineage, (@idx + 1) * @lEntry + @lNick + 2, 1) > substring(lineage, @idx * @lEntry + @lNick + 2, 1) and
  1414.                             substring(lineage, (@idx + 1) * @lEntry + @lNick + 3, 2) = substring(lineage, @idx * @lEntry + @lNick + 3, 2))
  1415.                         or
  1416.                         -- 3rd least significant version byte at second entry is higher, the most significant byte is equal
  1417.                         (substring(lineage, (@idx + 1) * @lEntry + @lNick + 3, 1) > substring(lineage, @idx * @lEntry + @lNick + 3, 1) and
  1418.                             substring(lineage, (@idx + 1) * @lEntry + @lNick + 4, 1) = substring(lineage, @idx * @lEntry + @lNick + 4, 1))
  1419.                         or
  1420.                         -- most significant byte at second entry is higher
  1421.                         substring(lineage, (@idx + 1) * @lEntry + @lNick + 4, 1) > substring(lineage, @idx * @lEntry + @lNick + 4, 1)
  1422.                     )
  1423.  
  1424.             if @@error<>0
  1425.             begin
  1426.                 return (1)
  1427.             end
  1428.  
  1429.             set @idx= @idx - 1
  1430.         end
  1431.     end
  1432.     return (0)
  1433. go
  1434.  
  1435. exec dbo.sp_MS_marksystemobject sp_MSfixlineageversions 
  1436. go
  1437. grant exec on dbo.sp_MSfixlineageversions to public
  1438. go
  1439.  
  1440. dump tran master with no_log
  1441. go
  1442.  
  1443. raiserror('Creating procedure sp_MSaddupdatetrigger', 0,1)
  1444. GO
  1445.  
  1446. CREATE PROCEDURE sp_MSaddupdatetrigger 
  1447.     @source_table        nvarchar(270),        /* source table name */
  1448.     @owner                sysname,            /* Owner name of source table */
  1449.     @object             sysname,            /* Object name */
  1450.     @artid                uniqueidentifier,    /* Article id */
  1451.     @column_tracking        int,
  1452.     @viewname            sysname             /* name of view on syscontents */
  1453.     
  1454. AS
  1455.     declare @command1 nvarchar(4000)
  1456.     declare @command2 nvarchar(4000)
  1457.     declare @command3 nvarchar(4000)
  1458.     declare @command4 nvarchar(4000)
  1459.     declare @inscommand nvarchar(2000)
  1460.     declare @tablenick int    
  1461.     declare @nickname int
  1462.     declare @viewcols int
  1463.     declare @trigname sysname
  1464.     declare @ext nvarchar(10)
  1465.     declare @gstr sysname
  1466.     declare @tablenickchar nvarchar(11)
  1467.     declare @ccols int
  1468.     declare @guidstr    nvarchar(32)
  1469.     declare @colid smallint
  1470.     declare @colordinal        smallint
  1471.     declare @colordstr        varchar(4)
  1472.  
  1473.     declare @colname     sysname
  1474.     declare @cur_name    sysname
  1475.     declare @colpat nvarchar(130)
  1476.     declare @colchar nvarchar(5)
  1477.     declare @piece nvarchar(400)
  1478.  
  1479.     declare @retcode int
  1480.     declare @ifcol nvarchar(4000)
  1481.     declare @ccolchar nvarchar(5)
  1482.     declare @partchangecnt int
  1483.     declare @joinchangecnt int
  1484.     declare @partchangecnt2 int
  1485.     declare @cvstr1    nvarchar(500)
  1486.     declare @cvstr2 nvarchar(500)
  1487.     declare @flag smallint
  1488.     declare @missingbm varbinary(500)
  1489.     declare @missing_cols    varbinary(32)
  1490.     declare @mapdownbm varbinary(500)
  1491.     declare @mapupbm   varbinary(500)
  1492.     declare @missingcolid int
  1493.     declare @maxcolid int
  1494.     declare @missingbmstr varchar(1000)
  1495.     declare @mapdownbmstr varchar(1000)
  1496.     declare @mapupbmstr   varchar(1000)
  1497.     declare @objid int
  1498.     declare @sync_objid int
  1499.     declare @partchbm varbinary(500)
  1500.     declare @missing_col_count    int
  1501.     declare @excluded_col_count int
  1502.     declare @joinchbm varbinary(500)
  1503.     declare @partchstr varchar(1002)
  1504.     declare @joinchstr varchar(1002)
  1505.     declare @column_hole bit
  1506.     declare @notforrepl_bit bit
  1507.     declare @notforrepl_str nvarchar(200)
  1508.     declare @owner_is_admin bit
  1509.     
  1510.     set @notforrepl_bit = 1
  1511.     set @ifcol = ''
  1512.     set @column_hole = 0
  1513.     set @owner_is_admin = 0
  1514.     
  1515.     select @owner_is_admin=sysadmin from master..syslogins l, sysusers u where l.sid=u.sid and u.name=@owner collate database_default
  1516.     select @flag = 0
  1517.     set @objid = OBJECT_ID(@source_table)
  1518.     select @sync_objid = sync_objid, @missing_cols = missing_cols, @excluded_col_count = excluded_col_count,
  1519.                                     @missing_col_count=missing_col_count 
  1520.                     from sysmergearticles where artid= @artid and objid=@objid
  1521.     select @ccols =  count(*) from syscolumns where id = @objid and iscomputed <> 1 and type_name(xtype) <> 'timestamp'
  1522.     /* Figure out if there are any holes in the colid sequence */
  1523.     select @maxcolid = max(colid) from syscolumns where id = @objid
  1524.     if @ccols <> @maxcolid
  1525.         select @column_hole = 1
  1526.     /*
  1527.     ** adjust the number of columns in the original table by adding up missing columns; in both Pub/Sub sides.
  1528.     */
  1529.     if @missing_col_count>0
  1530.         select @ccols = @ccols + @missing_col_count
  1531.     select @ccolchar = convert(nchar, @ccols)
  1532.     set @colordinal = 0
  1533.     
  1534.     execute @retcode=sp_MStablenickname @owner, @object, @tablenick output
  1535.     if @@ERROR<>0 or @retcode<>0 return (1)
  1536.     set @tablenickchar = convert(nchar, @tablenick)
  1537.     set @joinchbm = 0x0
  1538.     set @partchbm = 0x0
  1539.  
  1540.     -- Check if the update trigger can be made NOT FOR REPLICATION
  1541.     if exists (select * from sysmergearticles 
  1542.                where nickname = @tablenick 
  1543.                and
  1544.                (before_image_objid is not null or
  1545.                 before_view_objid is not null or
  1546.                 datalength (subset_filterclause) > 1
  1547.                ))
  1548.     begin
  1549.         select @notforrepl_bit = 0
  1550.     end
  1551.     else if exists (select * from sysmergesubsetfilters where art_nickname = @tablenick or join_nickname = @tablenick)
  1552.     begin
  1553.         select @notforrepl_bit = 0
  1554.     end
  1555.     else
  1556.     begin
  1557.         select @notforrepl_bit = 1
  1558.     end
  1559.     
  1560.     if exists (select * from dbo.sysmergearticles where nickname = @tablenick and published_in_tran_pub = 1)
  1561.     begin
  1562.         select @notforrepl_str = ' 
  1563.     if sessionproperty(''replication_agent'') = 1 and (select trigger_nestlevel()) = 1 and master.dbo.fn_isreplmergeagent() = 1
  1564.         return '
  1565.     end
  1566.     else
  1567.     begin
  1568.         select @notforrepl_str = ' 
  1569.     if sessionproperty(''replication_agent'') = 1 and (select trigger_nestlevel()) = 1
  1570.         return '
  1571.     end
  1572.         
  1573.     declare col_cursor CURSOR LOCAL FAST_FORWARD for select name, colid from syscolumns where
  1574.         id = @objid  and iscomputed <> 1 and type_name(xtype) <> 'timestamp' order by colid
  1575.     FOR READ ONLY
  1576.     
  1577.     /* Try to set the ifcol pieces of the trigger */
  1578.     open col_cursor
  1579.     fetch next from col_cursor into @colname, @colid
  1580.     while (@@fetch_status <> -1)
  1581.         begin
  1582.         set @colordinal = @colordinal + 1
  1583.         set @colpat = '%' + @colname + '%'
  1584.         /* Don't let them update the rowguid column */
  1585.         if columnproperty( @objid, @colname , 'isrowguidcol')=1
  1586.             set @ifcol = 'if update(' + QUOTENAME(@colname) +    ')
  1587.             begin
  1588.             if @@trancount > 0
  1589.                 rollback tran
  1590.                 
  1591.             RAISERROR (20062, 16, -1)
  1592.             end
  1593.                 '
  1594.         /* does updating this column change membership in a partial replica? */
  1595.         select @partchangecnt = count(*) from sysmergearticles 
  1596.             where nickname = @tablenick and subset_filterclause like @colpat
  1597.         select @partchangecnt2 = count(*) from sysmergesubsetfilters
  1598.             where art_nickname = @tablenick and join_filterclause like @colpat
  1599.         select @joinchangecnt = count(*) from sysmergesubsetfilters
  1600.              where join_nickname = @tablenick and join_filterclause like @colpat
  1601.         if @partchangecnt > 0 or @partchangecnt2 > 0
  1602.             exec dbo.sp_MSsetbit @partchbm out, @colid
  1603.         else if @joinchangecnt > 0
  1604.             exec dbo.sp_MSsetbit @joinchbm out, @colid
  1605.         /* Repeat the loop with next column */
  1606.         fetch next from col_cursor into @colname, @colid
  1607.         end
  1608.     close col_cursor
  1609.     deallocate col_cursor
  1610.  
  1611.     -- Initialize string for inserting to before_image table
  1612.     exec sp_MSgetbeforetableinsert @objid, @inscommand output
  1613.  
  1614.     /* Make strings to initialize variables for partchange, joinchange bitmaps */
  1615.     exec master..xp_varbintohexstr @partchbm, @partchstr out
  1616.     exec master..xp_varbintohexstr @joinchbm, @joinchstr out
  1617.  
  1618.     select @mapdownbm =0x00
  1619.     select @mapupbm = 0x00
  1620.     /*
  1621.     ** To see if there is a need for map down.
  1622.     */
  1623.     if @column_hole<>0
  1624.     begin
  1625.         set @missingcolid = 1
  1626.         while (@missingcolid <= @maxcolid)
  1627.             begin
  1628.             if not exists (select * from syscolumns where colid = @missingcolid and
  1629.                         id = OBJECT_ID(@source_table) and iscomputed <> 1 and type_name(xtype) <> 'timestamp')
  1630.                     exec dbo.sp_MSsetbit @mapdownbm out, @missingcolid
  1631.             set @missingcolid = @missingcolid + 1
  1632.             end
  1633.     end
  1634.     set @mapupbm = @missing_cols -- do this at both sides, good for republishing.
  1635.     
  1636.     exec master..xp_varbintohexstr @mapdownbm, @mapdownbmstr out
  1637.     exec master..xp_varbintohexstr @mapupbm, @mapupbmstr out
  1638.     
  1639.     execute @retcode=sp_MSgetreplnick @nickname = @nickname output
  1640.     if @retcode<>0 or @@error<>0 return (1)
  1641.     set @ext = 'upd_'
  1642.  
  1643.     exec @retcode=sp_MSguidtostr @artid, @guidstr out
  1644.     if @retcode<>0 or @@error<>0 return (1)
  1645.  
  1646.     set @trigname =  @ext + @guidstr 
  1647.  
  1648.     /* Make sure trigger name is unique */
  1649.     exec @retcode=sp_MSuniqueobjectname @trigname, @trigname output
  1650.     if @retcode<>0 or @@error<>0 return (1)
  1651.     if @column_tracking <> 0
  1652.         begin
  1653.         /* Set cv pieces appropriately */
  1654.         set @cvstr1 = ' 
  1655.             set @lineage = { fn UPDATELINEAGE(0x0, @nick, @oldmaxversion+1) }
  1656.             set @cv = { fn INITCOLVS(@ccols, @nick) }
  1657.             if (@@error <> 0)
  1658.                 begin
  1659.                 goto FAILURE
  1660.                 end
  1661.             set @cv = { fn UPDATECOLVBM(@cv, @nick, @bm, @missingbm, { fn GETMAXVERSION(@lineage) }) }
  1662.         '
  1663.         set @cvstr2 = '
  1664.                 colv1 = { fn UPDATECOLVBM(colv1, @nick, @bm, @missingbm, { fn GETMAXVERSION({ fn UPDATELINEAGE(lineage, @nick, @oldmaxversion+1) }) }) } '
  1665.         end
  1666.     else
  1667.         begin
  1668.         set @cvstr1 = '   set @lineage = { fn UPDATELINEAGE(0x0, @nick, @oldmaxversion+1) }
  1669.             set @cv = NULL
  1670.      '
  1671.         set @cvstr2 = ' colv1 = NULL '
  1672.         end
  1673.     /* UNDONE maybe remove null guid checks in SQL SERVER 7.0 */
  1674.     select @command1 = 'create trigger ' + @trigname + ' on ' + @source_table +
  1675.     ' FOR UPDATE AS '
  1676.  
  1677.     if (@notforrepl_bit = 1)
  1678.         select @command1 = @command1 + @notforrepl_str
  1679.  
  1680.     select @command1 = @command1 + ' 
  1681.     /* Declare variables */
  1682.  
  1683.     declare @article_rows_updated int
  1684.     select @article_rows_updated = count(*) from inserted
  1685.     declare @contents_rows_updated int, @updateerror int
  1686.     declare @bm varbinary(500), @missingbm varbinary(500), @lineage varbinary(255), @cv varbinary(2048)
  1687.     declare @tablenick int, @nick int, @ccols int, @partchange int, @joinchange int
  1688.     declare    @partchangebm varbinary(500), @joinchangebm varbinary(500)
  1689.     declare @oldmaxversion int
  1690.         
  1691.     set nocount on
  1692.     set @tablenick = ' + @tablenickchar + '
  1693.     select @oldmaxversion= maxversion_at_cleanup from dbo.sysmergearticles where nickname = @tablenick
  1694.     
  1695.     /* Use intrinsic funtion to set bits for updated columns */
  1696.     set @bm = columns_updated()
  1697.  
  1698.     /* only do the map down when needed */
  1699.     set @missingbm = ' 
  1700.  
  1701.     select @command2 = '  
  1702.  
  1703.     /* See if the partition might have changed */
  1704.     if @partchangebm = 0x0
  1705.         set @partchange = 0
  1706.     else
  1707.         set @partchange= { fn INTERSECTBITMAPS (@bm, @partchangebm) }
  1708.     
  1709.     /* See if a column used in a join filter changed */
  1710.     if @joinchangebm = 0x0
  1711.         set @joinchange = 0
  1712.     else
  1713.         set @joinchange= { fn INTERSECTBITMAPS (@bm, @joinchangebm) }
  1714.     '
  1715.  
  1716.     if @mapdownbm<>0x00
  1717.         select @command2 = @command2 + 
  1718.                 ' execute master..xp_mapdown_bitmap ' + @mapdownbmstr +', @bm output '
  1719.  
  1720.     select @command2 = @command2 + '
  1721.  
  1722.     exec dbo.sp_MSgetreplnick @nickname = @nick output
  1723.     select @ccols = ' + @ccolchar + '
  1724.     ' + @cvstr1 + '
  1725.         ' 
  1726.     set @command3 = '
  1727.  
  1728.     update ' + @viewname + ' 
  1729.     set lineage = { fn UPDATELINEAGE(lineage, @nick, @oldmaxversion+1) }, 
  1730.         generation = A.gen_cur, 
  1731.         joinchangegen = case when (@joinchange = 1) then A.gen_cur else joinchangegen end, 
  1732.         partchangegen = case when (@partchange = 1) then A.gen_cur else partchangegen end, 
  1733.         ' + @cvstr2 + ' 
  1734.     FROM inserted as I JOIN ' + @viewname + ' as V 
  1735.     ON (I.rowguidcol=V.rowguid)
  1736.     and V.tablenick = @tablenick
  1737.     JOIN (select top 1 nickname, gen_cur = isnull(gen_cur, 0) from dbo.sysmergearticles where nickname = @tablenick) as A
  1738.     ON V.tablenick = A.nickname
  1739.  
  1740.     select @updateerror = @@error, @contents_rows_updated = @@rowcount
  1741.      ' + case when @inscommand is null or @inscommand = ' ' then ' ' else ' if @joinchange = 1 or @partchange = 1 ' + @inscommand end + ' 
  1742.     if @article_rows_updated <> @contents_rows_updated
  1743.     begin
  1744.  
  1745.         insert into ' + @viewname + ' (tablenick, rowguid, lineage, colv1, generation, partchangegen, joinchangegen) 
  1746.             select @tablenick, rowguidcol, @lineage, @cv, A.gen_cur, 
  1747.             case when (@joinchange = 1 or @partchange = 1) then A.gen_cur else NULL end, 
  1748.             case when @joinchange = 1 then A.gen_cur else NULL end
  1749.             from inserted,
  1750.             (select top 1 nickname, gen_cur = isnull(gen_cur, 0) from dbo.sysmergearticles where nickname = @tablenick) as A
  1751.             where rowguidcol not in (select rowguid from ' + @viewname + ' where tablenick = @tablenick)
  1752.  
  1753.         if @@error <> 0
  1754.             GOTO FAILURE
  1755.     end
  1756.  
  1757.  
  1758.     return
  1759. FAILURE:
  1760.                 if @@trancount > 0
  1761.                     rollback tran
  1762.                 raiserror (20041, 16, -1)
  1763.                 return
  1764.                     '
  1765.             
  1766.     execute (@command1 + @mapupbmstr + '
  1767.         set @partchangebm = ' + @partchstr + '
  1768.         set @joinchangebm = ' + @joinchstr + '
  1769.             ' + @ifcol +  
  1770.             @command2 + @command3)
  1771.     if @@ERROR <> 0 
  1772.         begin
  1773.             raiserror(20064, 16, -1)
  1774.             return (1)
  1775.         end
  1776.     
  1777.     select @command4 = @owner + '.' + @trigname
  1778.     if @owner_is_admin=1
  1779.     begin
  1780.         exec sp_MS_marksystemobject @command4
  1781.         if @@ERROR <> 0 
  1782.             begin
  1783.                 raiserror(20064, 16, -1)
  1784.                 return (1)
  1785.             end
  1786.     end
  1787. GO
  1788.  
  1789. exec dbo.sp_MS_marksystemobject sp_MSaddupdatetrigger
  1790. go
  1791.  
  1792. raiserror('Creating procedure sp_MSaddmergetriggers', 0,1)
  1793. GO
  1794. CREATE PROCEDURE sp_MSaddmergetriggers 
  1795.     @source_table         nvarchar(270),                /* was type varchar(92), table name */
  1796.     @table_owner        sysname = NULL,
  1797.     @column_tracking     int = NULL                /* Is column tracking on - default is FALSE */
  1798. AS
  1799.     set nocount on
  1800.     declare @command        nvarchar(4000)
  1801.     declare @command2 nvarchar(4000)
  1802.     declare @inscommand nvarchar(2000)
  1803.     declare @ifcoltracking     nvarchar(255)
  1804.     declare @tablenick         int    
  1805.     declare @nickname         int
  1806.     declare @artid             uniqueidentifier
  1807.     declare @guidstr        nvarchar(32)
  1808.     declare @owner             sysname
  1809.     declare @site             sysname
  1810.     declare @db             sysname
  1811.     declare @object         sysname
  1812.     declare @updtrigname         sysname
  1813.     declare @instrigname         sysname
  1814.     declare @deltrigname         sysname
  1815.     declare @ext                 nvarchar(10)
  1816.     declare @ext2                 nvarchar(10)
  1817.     declare @tablenickchar         nvarchar(11)
  1818.     declare @missing_col_count    int
  1819.     declare @ccols             int
  1820.     declare @ccolchar         nvarchar(5)
  1821.     declare @retcode         int
  1822.     declare @objid            int
  1823.     declare @bitmap         varbinary(40)
  1824.     declare @missing_count    int
  1825.     declare @viewname        sysname
  1826.     declare @tsview            sysname
  1827.     declare @sync_objid        int
  1828.     declare @command3       nvarchar(4000)
  1829.     declare @notforrepl_str    nvarchar(200)
  1830.     declare @notforrepl_bit bit
  1831.     declare @owner_is_admin bit
  1832.     
  1833.     set @notforrepl_bit = 1
  1834.     set @owner_is_admin = 0
  1835.     set @bitmap = 0x0
  1836.     set @missing_count = 0
  1837.  
  1838.        /* Security check */
  1839.     EXEC @retcode = dbo.sp_MSreplcheck_subscribe
  1840.     if @@ERROR <> 0 or @retcode <> 0
  1841.         return(1)
  1842.  
  1843.     -- PARSENAME VARS
  1844.     declare      @UnqualName      sysname  --rightmost name node
  1845.     declare      @QualName1       sysname  
  1846.     -- END PARSENAME VARS
  1847.  
  1848.     execute @retcode=sp_MSgetreplnick @nickname = @nickname output
  1849.     if @retcode<>0 or @@ERROR<>0 return (1)
  1850.  
  1851.     select @ext = 'ins_'
  1852.     select @ext2 = 'del_'
  1853.     if @table_owner is not NULL
  1854.         select @source_table=QUOTENAME(@table_owner) + '.' + QUOTENAME(@source_table)
  1855.         
  1856.     set @objid =  OBJECT_ID(@source_table)
  1857.  
  1858.     -- set up the before image table if one is desired
  1859.     exec dbo.sp_MScreatebeforetable @objid
  1860.  
  1861.     select @ccols =  count(*) from syscolumns where id = @objid  and iscomputed <> 1 and type_name(xtype) <> 'timestamp'
  1862.     select @missing_col_count=missing_col_count, @sync_objid=sync_objid from sysmergearticles where objid=@objid
  1863.     /*
  1864.     ** increase the # of columns at subscriber side by adding the missing columns
  1865.     ** Note that publisher side also needs to increase this value due to the possible column holes.
  1866.     */
  1867.     select @ccols = @ccols + @missing_col_count
  1868.     select @ccolchar = convert(nchar, @ccols)
  1869.  
  1870.     select @UnqualName = PARSENAME(@source_table, 1)
  1871.     select @QualName1 = PARSENAME(@source_table, 2)
  1872.     if @UnqualName IS NULL
  1873.          return 1
  1874.  
  1875.     if @QualName1 is NULL
  1876.          select @QualName1 = user_name(uid) from sysobjects where id = object_id(@UnqualName)
  1877.  
  1878.     -- fixup for variable length differences.  remove when vars expanded
  1879.     -- to new SQL SERVER 7.0 lengths
  1880.  
  1881.     select @owner = @QualName1
  1882.     select @object = @UnqualName
  1883.  
  1884.     --this is to find out if table owner is a system user
  1885.     select @owner_is_admin=sysadmin from master..syslogins l, sysusers u where l.sid=u.sid and u.name=@owner collate database_default
  1886.         
  1887.     execute @retcode=sp_MStablenickname @owner, @object, @tablenick output
  1888.     if @retcode<>0 or @@ERROR<>0 return (1)
  1889.     select @artid = artid from sysmergearticles 
  1890.         where objid = @objid
  1891.         
  1892.     /* If column tracking wasn't passed in, just figure it out */
  1893.     if @column_tracking is null
  1894.         select @column_tracking = column_tracking from sysmergearticles 
  1895.         where artid = @artid
  1896.         
  1897.     select @tablenickchar = convert(nchar, @tablenick)
  1898.     exec @retcode=sp_MSguidtostr @artid, @guidstr out
  1899.     if @retcode<>0 or @@ERROR<>0 return (1)
  1900.  
  1901.     -- Check if the triggers can be made NOT FOR REPLICATION
  1902.     if exists (select * from sysmergearticles 
  1903.                where nickname = @tablenick 
  1904.                and
  1905.                (before_image_objid is not null or
  1906.                 before_view_objid is not null or
  1907.                 datalength (subset_filterclause) > 1
  1908.                ))
  1909.     begin
  1910.         select @notforrepl_bit = 0
  1911.     end
  1912.     else if exists (select * from sysmergesubsetfilters where art_nickname = @tablenick or join_nickname = @tablenick)
  1913.     begin
  1914.         select @notforrepl_bit = 0
  1915.     end
  1916.     else
  1917.     begin
  1918.         select @notforrepl_bit = 1
  1919.     end
  1920.     
  1921.     if exists (select * from dbo.sysmergearticles where nickname = @tablenick and published_in_tran_pub = 1)
  1922.     begin
  1923.         select @notforrepl_str = ' 
  1924.     if sessionproperty(''replication_agent'') = 1 and (select trigger_nestlevel()) = 1 and master.dbo.fn_isreplmergeagent() = 1
  1925.         return '
  1926.     end
  1927.     else
  1928.     begin
  1929.         select @notforrepl_str = ' 
  1930.     if sessionproperty(''replication_agent'') = 1 and (select trigger_nestlevel()) = 1
  1931.         return '
  1932.     end
  1933.  
  1934.     /* Drop the article's replication triggers if they preexist */
  1935.     exec dbo.sp_MSdroparticletriggers @source_table, @table_owner
  1936.     if @@ERROR <> 0
  1937.         return 1
  1938.     
  1939.     -- owner name removed
  1940.     set @instrigname = @ext + @guidstr 
  1941.     set @deltrigname = @ext2 + @guidstr
  1942.     set @updtrigname = 'upd_' + @guidstr
  1943.     set @viewname = 'ctsv_' + @guidstr
  1944.     set @tsview = 'tsvw_' + @guidstr
  1945.     
  1946.     /* Make sure trigger name is unique */
  1947.     exec @retcode=sp_MSuniqueobjectname @instrigname, @instrigname output
  1948.     if @retcode<>0 or @@ERROR<>0 return (1)
  1949.     exec @retcode=sp_MSuniqueobjectname @deltrigname, @deltrigname output
  1950.     if @retcode<>0 or @@ERROR<>0 return (1)
  1951.     exec @retcode=sp_MSuniqueobjectname @updtrigname, @updtrigname output
  1952.     if @retcode<>0 or @@ERROR<>0 return (1)
  1953.  
  1954.  
  1955.     -- check if there is a before image table. If so create a view from which public can select
  1956.     declare @before_name sysname
  1957.     declare @beforeview sysname
  1958.     select @before_name = OBJECT_NAME(before_image_objid) from sysmergearticles where objid = @objid
  1959.     set @beforeview = 'MSbivw_' + @guidstr
  1960.     if (@before_name is not null)
  1961.     begin
  1962.         /* Create the a view on the before image table if it doesn't already exist. */
  1963.         /* this view is needed for security purposes since we don't want to grant rights 
  1964.            on the before image table to all users */
  1965.         if not exists (select * from sysobjects where type = 'V' and name = @beforeview)
  1966.         begin
  1967.             exec @retcode=sp_MSuniqueobjectname @beforeview, @beforeview output
  1968.             if @retcode<>0 or @@ERROR<>0 return (1)
  1969.             set @command = 'create view dbo.' + @beforeview + ' as
  1970.                 select * from dbo.' + @before_name + ' where
  1971.                     trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@instrigname) + ''')) > 0 or
  1972.                     trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@updtrigname) + ''')) > 0 or
  1973.                     trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@deltrigname) + ''')) > 0
  1974.                     with check option'
  1975.             execute (@command)
  1976.             if @@ERROR<>0 return (1)
  1977.             set @command = 'grant update, insert, select, delete on ' + @beforeview + ' to public'
  1978.             execute (@command)
  1979.             if @@ERROR<>0 return (1)
  1980.             exec sp_MS_marksystemobject  @beforeview 
  1981.             if @@ERROR<>0 return (1)    
  1982.         end
  1983.     end
  1984.  
  1985.     -- Initialize string for inserting to before_image table
  1986.     -- moved this here because it will use the beforeimage table ciew created above.
  1987.     exec sp_MSgetbeforetableinsert @objid, @inscommand output
  1988.  
  1989.     /* Create the view if it doesn't already exist. */
  1990.     if not exists (select * from sysobjects where type = 'V' and name = @viewname)
  1991.         begin
  1992.  
  1993.         exec @retcode=sp_MSuniqueobjectname @viewname, @viewname output
  1994.         if @retcode<>0 or @@ERROR<>0 return (1)
  1995.         set @command = 'create view dbo.' + @viewname + ' as
  1996.             select * from dbo.MSmerge_contents where
  1997.                 trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@instrigname) + ''')) > 0 or
  1998.                 trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@updtrigname) + ''')) > 0 or
  1999.                 trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@deltrigname) + ''')) > 0
  2000.                 with check option'
  2001.         execute (@command)
  2002.         if @@ERROR<>0 return (1)
  2003.         set @command = 'grant update, insert, select, delete on ' + @viewname + ' to public'
  2004.         execute (@command)
  2005.         if @@ERROR<>0 return (1)
  2006.         exec sp_MS_marksystemobject @viewname
  2007.         if @@ERROR<>0 return (1)    
  2008.         end
  2009.  
  2010.  
  2011.     /* Create the view if it doesn't already exist. */
  2012.     if not exists (select * from sysobjects where type = 'V' and name = @tsview)
  2013.         begin
  2014.         exec @retcode=sp_MSuniqueobjectname @tsview, @tsview output
  2015.         if @retcode<>0 or @@ERROR<>0 return (1)
  2016.         set @command = 'create view dbo. ' + @tsview + ' as
  2017.             select * from dbo.MSmerge_tombstone where
  2018.                 trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@instrigname) + ''')) > 0 or
  2019.                 trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@updtrigname) + ''')) > 0 or
  2020.                 trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@deltrigname) + ''')) > 0
  2021.                 with check option'
  2022.         execute (@command)
  2023.         if @@ERROR<>0 return (1)
  2024.         set @command = 'grant update, insert, select, delete on ' + @tsview + ' to public'
  2025.         execute (@command)
  2026.         if @@ERROR<>0 return (1)        
  2027.         exec sp_MS_marksystemobject @tsview
  2028.         if @@ERROR<>0 return (1)    
  2029.         end
  2030.  
  2031.     /* If column tracking is on, construct the string to initialize colv's */
  2032.     if (@column_tracking <> 0)
  2033.         select @ifcoltracking = '    set @colv1 = { fn INITCOLVS(@ccols, @nickname) }'
  2034.     else
  2035.         select @ifcoltracking = '    set @colv1 = NULL'
  2036.         
  2037.     /* UNDONE maybe remove null guid checks in SQL SERVER 7.0 */
  2038.     select @command = 'create trigger ' + @instrigname + ' on ' + @source_table +
  2039.         ' for insert as ' + @notforrepl_str + ' 
  2040.         /* Declare variables */
  2041.         declare @article_rows_inserted int
  2042.         select @article_rows_inserted = count(*) from inserted
  2043.         declare @tablenick int, @nickname int
  2044.         declare @lineage varbinary(255), @colv1 varbinary(2048)
  2045.         declare @ccols int, @retcode smallint, @version int, @curversion int, @oldmaxversion int
  2046.         
  2047.         set nocount on
  2048.         set @tablenick = ' + @tablenickchar + '
  2049.         select @ccols = ' + @ccolchar + '
  2050.         set @lineage = 0x0
  2051.         set @retcode = 0
  2052.         select @oldmaxversion= maxversion_at_cleanup from dbo.sysmergearticles where nickname = @tablenick
  2053.         
  2054.         execute dbo.sp_MSgetreplnick @nickname = @nickname output
  2055.         if (@@error <> 0)
  2056.             begin
  2057.             goto FAILURE
  2058.             end
  2059.         set @lineage = { fn UPDATELINEAGE (0x0, @nickname, 1) }
  2060.         ' + @ifcoltracking + '
  2061.         if (@@error <> 0)
  2062.             begin
  2063.             goto FAILURE
  2064.             end
  2065.  
  2066.         if exists (select ts.rowguid from ' + @tsview + ' ts, inserted i where ts.tablenick = @tablenick and ts.rowguid = i.rowguidcol)
  2067.         begin
  2068.             select @version = max({fn GETMAXVERSION(lineage)}) from ' + @tsview + ' where 
  2069.                 tablenick = @tablenick and rowguid in (select rowguidcol from inserted)
  2070.  
  2071.             if @version is not null
  2072.             begin
  2073.                 -- reset lineage and colv to higher version...
  2074.                 set @curversion = 0
  2075.                 while (@curversion <= @version)
  2076.                 begin
  2077.                     set @lineage = { fn UPDATELINEAGE (@lineage, @nickname, @oldmaxversion+1) }
  2078.                     set @curversion = @curversion + 1
  2079.                 end
  2080.  
  2081.                 if (@colv1 IS NOT NULL)
  2082.                     set @colv1 = { fn UPDATECOLVBM(@colv1, @nickname, 0x01, 0x00, { fn GETMAXVERSION(@lineage) }) }
  2083.                 
  2084.                 delete from ' + @tsview + ' where tablenick = @tablenick and rowguid in
  2085.                     (select rowguidcol from inserted)
  2086.             end
  2087.         end
  2088.  
  2089.         if (@article_rows_inserted = 1)
  2090.         begin
  2091.             if not exists (select ct.rowguid from ' + @viewname + ' ct, inserted i where ct.tablenick = @tablenick and ct.rowguid = i.rowguidcol)
  2092.             begin
  2093.                 insert into ' + @viewname + ' (tablenick, rowguid, lineage, colv1, generation, joinchangegen) select
  2094.                     @tablenick, rowguidcol, @lineage, @colv1, A.gen_cur, A.gen_cur from inserted,
  2095.                 (select top 1 nickname, gen_cur = isnull(gen_cur, 0) from dbo.sysmergearticles where nickname = @tablenick) as A
  2096.             end
  2097.         end
  2098.         else
  2099.         begin
  2100.             insert into ' + @viewname + ' (tablenick, rowguid, lineage, colv1, generation, joinchangegen) select
  2101.                 @tablenick, rowguidcol, @lineage, @colv1, A.gen_cur, A.gen_cur from inserted,
  2102.                 (select top 1 nickname, gen_cur = isnull(gen_cur, 0) from dbo.sysmergearticles where nickname = @tablenick) as A
  2103.                 where rowguidcol not in (select rowguid from ' + @viewname + ' where tablenick = @tablenick)
  2104.         end
  2105.         if @@error <> 0 
  2106.             goto FAILURE
  2107.         return
  2108.     FAILURE:
  2109.  
  2110.                 if @@trancount > 0
  2111.                     rollback tran
  2112.                 raiserror (20041, 16, -1)
  2113.                 return
  2114.                     '
  2115.     execute (@command)
  2116.     if @@ERROR <> 0 
  2117.         begin
  2118.             raiserror(21304, 16, -1, @source_table)
  2119.             return (1)
  2120.         end
  2121.     
  2122.     select @command3 = @owner + '.'  + @instrigname 
  2123.     if @owner_is_admin = 1
  2124.     begin
  2125.         exec sp_MS_marksystemobject @command3
  2126.         if @@ERROR <> 0 
  2127.             begin
  2128.                 raiserror(21304, 16, -1, @source_table)
  2129.                 return (1)
  2130.             end
  2131.     end
  2132.     /* Call separate routine to add update trigger */
  2133.     exec @retcode=sp_MSaddupdatetrigger @source_table, @owner, @object, @artid, @column_tracking, @viewname
  2134.     if @retcode<>0 or @@ERROR<>0 return (1)
  2135.  
  2136.     /* Now make the delete trigger */
  2137.     -- NOTE: owner name removed
  2138.  
  2139.     /* Make sure trigger name is unique */
  2140.     exec @retcode = dbo.sp_MSuniqueobjectname @deltrigname, @deltrigname output
  2141.     if @retcode<>0 or @@ERROR<>0 return (1)
  2142.  
  2143.     set @command = 'create trigger ' + @deltrigname + ' on ' + @source_table +
  2144.     ' FOR DELETE AS '
  2145.  
  2146.     if (@notforrepl_bit = 1)
  2147.         select @command = @command + @notforrepl_str
  2148.  
  2149.     select @command = @command + '
  2150.     /* Declare variables */
  2151.     declare @tablenick int, @retcode smallint, @reason nvarchar(255), @nickname int, @lineage varbinary(255), @oldmaxversion int
  2152.     
  2153.     set nocount on
  2154.     select @tablenick = ' + @tablenickchar + '
  2155.     select @oldmaxversion= maxversion_at_cleanup from dbo.sysmergearticles where nickname = @tablenick
  2156.     
  2157.     select @reason = ''user delete''
  2158.     execute dbo.sp_MSgetreplnick @nickname = @nickname output
  2159.     if (@@error <> 0)
  2160.         begin
  2161.         goto FAILURE
  2162.         end
  2163.     '
  2164.     set @command2 = '
  2165.     set @lineage = { fn UPDATELINEAGE(0x0, @nickname, @oldmaxversion) }
  2166.  
  2167.     insert into ' + @tsview + ' (rowguid, tablenick, type, lineage, generation, reason)
  2168.         select rowguidcol, @tablenick, 1, { fn UPDATELINEAGE(COALESCE(c.lineage, @lineage), @nickname, @oldmaxversion+1) }, a.gen_cur, @reason from 
  2169.             deleted d left outer join ' + @viewname + ' c on c.tablenick = @tablenick and c.rowguid = d.rowguidcol
  2170.             join (select top 1 nickname, gen_cur = isnull(gen_cur, 0) from dbo.sysmergearticles where nickname = @tablenick) as a on a.nickname = @tablenick
  2171.     if @@error <> 0
  2172.         GOTO FAILURE
  2173.  
  2174.     delete from ' + @viewname + ' where tablenick = @tablenick and rowguid in 
  2175.         (select rowguidcol from deleted) 
  2176.     if @@error <> 0
  2177.         GOTO FAILURE
  2178.  
  2179.     
  2180.     return
  2181. FAILURE:
  2182.                 if @@trancount > 0
  2183.                     rollback tran
  2184.                 raiserror (20041, 16, -1)
  2185.                 return
  2186.                 '
  2187.     
  2188.     execute (@command + @inscommand + @command2)
  2189.  
  2190.     if @@ERROR <> 0 
  2191.         begin
  2192.             raiserror(21304, 16, -1, @source_table)
  2193.             return (1)
  2194.         end
  2195.     select @command3 = @owner + '.' + @deltrigname
  2196.     if @owner_is_admin = 1
  2197.     begin
  2198.         exec sp_MS_marksystemobject @command3
  2199.         if @@ERROR <> 0 
  2200.             begin
  2201.                 raiserror(21304, 16, -1, @source_table)
  2202.                 return (1)
  2203.             end
  2204.     end
  2205.     return (0)
  2206. GO
  2207.  
  2208. exec dbo.sp_MS_marksystemobject sp_MSaddmergetriggers 
  2209. go
  2210. grant exec on dbo.sp_MSaddmergetriggers to public
  2211. go
  2212.  
  2213. raiserror('Creating procedure sp_MShelpdestowner', 0,1)
  2214. GO
  2215.  
  2216. create procedure sp_MSchangeobjectowner(
  2217.     @tablename sysname,
  2218.     @dest_owner    sysname
  2219. )AS
  2220.     declare @uid         smallint
  2221.     declare @retcode    int
  2222.     
  2223.     -- Security check
  2224.     exec @retcode= sp_MSreplcheck_subscribe
  2225.     if @@error <> 0 or @retcode <> 0
  2226.     begin
  2227.         raiserror(15247, 11, -1)
  2228.         return (1)
  2229.     end
  2230.  
  2231.     select @uid=uid from sysobjects where name=@tablename
  2232.  
  2233.     --do not bother to call sp_changeobjectowner the object is owned by the @dest_owner itself
  2234.     if user_name(@uid)=@dest_owner
  2235.         return(0)
  2236.     exec @retcode=sp_changeobjectowner @tablename, @dest_owner
  2237.     if @@ERROR<>0 or @retcode<>0
  2238.     begin
  2239.         raiserror(21346, 16, -1, @tablename, @dest_owner)
  2240.         return (1)
  2241.     end
  2242.     return(0)    
  2243. go
  2244. exec dbo.sp_MS_marksystemobject sp_MSchangeobjectowner 
  2245. go
  2246. grant exec on dbo.sp_MSchangeobjectowner to public
  2247. go
  2248.  
  2249. create procedure sp_MShelpdestowner(
  2250. @spname sysname
  2251. )
  2252. AS
  2253.  
  2254. -- Security check
  2255. if not exists (select * from dbo.sysmergepublications where 1 = {fn ISPALUSER(pubid)})
  2256. begin    
  2257.     RAISERROR (15247, 11, -1)
  2258.     return (1)
  2259. end
  2260.  
  2261. declare @comment nvarchar(400)
  2262. declare @patindex int
  2263. declare @has_destowner    int
  2264. select @comment = convert(nvarchar(400), text) from syscomments where id = object_id(@spname)
  2265. select @patindex = PATINDEX('%@destowner%', @comment)
  2266. if @patindex<>0
  2267.     select 1
  2268. else
  2269.     select 0
  2270. GO
  2271. exec dbo.sp_MS_marksystemobject sp_MShelpdestowner 
  2272. go
  2273. grant exec on dbo.sp_MShelpdestowner to public
  2274. go
  2275.  
  2276.  
  2277. raiserror('Creating procedure sp_MSfillupmissingcols', 0,1)
  2278. GO
  2279.  
  2280. create procedure sp_MSfillupmissingcols(@publication sysname, @source_table sysname)
  2281. AS
  2282. declare @sync_objid         int
  2283. declare @columns            varbinary(125)
  2284. declare @missingcolid        int
  2285. declare @missingbm            varbinary(125)
  2286. declare @excludedcolid        int
  2287. declare @excludedbm            varbinary(125)
  2288. declare @excludedcolcnt        int
  2289. declare @missingcolcnt        int
  2290. declare @maxcolid            int
  2291. declare @column_tracking    bit
  2292. declare @id                    int
  2293. declare @pubid                uniqueidentifier
  2294. declare @missingindex        int
  2295. declare @retcode            int
  2296.  
  2297. -- Security check
  2298. exec @retcode= dbo.sp_MSreplcheck_publish
  2299. if @@error <> 0 or @retcode <> 0 return (1)
  2300.  
  2301. select @id = object_id(@source_table)
  2302. select @missingcolcnt = 0
  2303. select @excludedcolcnt = 0
  2304. select @pubid=pubid from sysmergepublications where name=@publication and publisher=@@SERVERNAME and publisher_db=db_name()
  2305. select @columns = columns, @sync_objid=sync_objid from sysmergearticles where objid = @id and pubid=@pubid
  2306. select @missingbm = 0x00
  2307. select @excludedbm = 0x00
  2308. select @missingcolid = 1 --instead of using the minimal colid in syscolumns with the same id, as we used to do 
  2309. select TOP 1 @maxcolid = colid from syscolumns where id=@id order by colid DESC
  2310.  
  2311. while (@missingcolid <= @maxcolid)
  2312.     begin
  2313.     if exists (select * from syscolumns where colid = @missingcolid and id = @id and 
  2314.                 name not in (select name from syscolumns where id = @sync_objid))
  2315.         begin
  2316.         select @excludedcolcnt = @excludedcolcnt + 1
  2317.         select @missingindex = count(*) from syscolumns where id=@id and colid<=@missingcolid
  2318.         exec dbo.sp_MSsetbit @excludedbm OUTPUT, @missingindex
  2319.         end
  2320.     set @missingcolid = @missingcolid + 1
  2321.     end
  2322.  
  2323. UPDATE sysmergearticles set excluded_col_count = @excludedcolcnt, 
  2324.                             excluded_cols = @excludedbm
  2325.         where objid = @id and pubid=@pubid
  2326. GO
  2327.  
  2328. exec dbo.sp_MS_marksystemobject sp_MSfillupmissingcols 
  2329. go
  2330. grant exec on dbo.sp_MSfillupmissingcols to public
  2331. go
  2332.  
  2333. raiserror('Creating procedure sp_MSmaptype', 0,1)
  2334. GO
  2335.  
  2336. create procedure sp_MSmaptype (@type nvarchar(60) output, 
  2337.                                 @len smallint, 
  2338.                                 @prec int, 
  2339.                                 @scale int)
  2340. as
  2341.     declare @typeout nvarchar(60)
  2342.  
  2343. select @typeout = case @type
  2344.     when 'binary' then 'varbinary'
  2345.     when 'char' then 'varchar'
  2346.     when 'nchar' then 'nvarchar'
  2347.     when 'datetimn' then 'datetime'
  2348.     when 'decimaln' then 'decimal'
  2349.     when 'floatn' then 'float'
  2350.     when 'intn' then 'int'
  2351.     when 'moneyn' then 'money'
  2352.     when 'numericn' then 'numeric'
  2353.     when 'timestamp' then 'varbinary'
  2354.     when 'bit' then 'tinyint'
  2355.     else @type  --for user defined data type which may contain space in between
  2356.     END
  2357. -- append length or scale and precision if needed
  2358. if (@typeout = 'varbinary' or @typeout = 'varchar' or @typeout = 'nvarchar')
  2359.     begin
  2360.     select @type = @typeout + '(' + rtrim(convert(nchar, @len)) + ')'
  2361.     return
  2362.     end
  2363. if (@typeout = 'numeric' or @typeout = 'decimal')
  2364.     begin
  2365.     select @type = @typeout + '(' + rtrim(convert(nchar, @prec)) + ',' + 
  2366.             rtrim(convert(nchar, @scale)) + ')'
  2367.     return
  2368.     end
  2369. select @type = @typeout
  2370. go
  2371.  
  2372. exec dbo.sp_MS_marksystemobject sp_MSmaptype 
  2373. go
  2374.  
  2375. raiserror('Creating procedure sp_MSquerysubtype', 0,1)
  2376. GO
  2377.  
  2378. create procedure sp_MSquerysubtype (@pubid uniqueidentifier,@subscriber sysname, @subscriber_db sysname)
  2379. as
  2380.     -- Security check
  2381.     if ({ fn ISPALUSER(@pubid)} <> 1)
  2382.     begin    
  2383.         RAISERROR (15247, 11, -1)
  2384.         return (1)
  2385.     end
  2386.     declare @subtype    int
  2387.     declare @srvid        int
  2388.  
  2389.     SELECT @srvid = srvid FROM master..sysservers WHERE UPPER(srvname) = UPPER(@subscriber) collate database_default
  2390.     
  2391.     select @subtype = NULL
  2392.     select @subtype = subscription_type from sysmergesubscriptions where pubid=@pubid 
  2393.         and db_name=@subscriber_db and srvid=@srvid
  2394.     if @subtype is NULL
  2395.         select @subtype=2
  2396.     select @subtype
  2397. go
  2398.  
  2399. exec dbo.sp_MS_marksystemobject sp_MSquerysubtype 
  2400. go
  2401.  
  2402. grant exec on dbo.sp_MSquerysubtype to public
  2403. go
  2404.  
  2405. -- sp_showrowreplicainfo displays row and column version information about a specific row
  2406. -- parameters: 
  2407. --         @ownername: The table owner.
  2408. --        @tablename: Name of the table that contains the row.
  2409. --        @rowguid: Unique identifier of the row of interest.
  2410. --        @show: Determines whether to display row versions, colum versions, or both. Values are 'both', 'row', or 'columns'.
  2411. -- output columns for row version information:
  2412. --        server_name: Name of the server that made this entry
  2413. --        db_name: Name of the database that made this entry.
  2414. --        db_nickname: Nickname of the database that made this entry.
  2415. --        version: Version of the entry.
  2416. --        rowversion_table: Indicates whether lineage is in MSmerge_contents or MSmerge_tombstone.
  2417. --        comment: Records problems with this version entry.
  2418. -- output columns for column version information:
  2419. --        server_name, db_name, db_nickname, version, comment: As above.
  2420. --        colname: Name of the column the colv entry stands for.
  2421. create procedure sp_showrowreplicainfo
  2422.     (@ownername sysname = NULL, @tablename sysname = NULL, @rowguid uniqueidentifier, @show nvarchar(20) = 'both')
  2423. as 
  2424.     set nocount on
  2425.  
  2426.     -- Security check
  2427.     if not exists (select * from dbo.sysmergearticles a join dbo.MSmerge_contents c 
  2428.                         on a.nickname=c.tablenick
  2429.                         where c.rowguid=@rowguid and
  2430.                               1 = {fn ISPALUSER(a.pubid)})
  2431.     begin    
  2432.         RAISERROR (15247, 11, -1)
  2433.         return (1)
  2434.     end
  2435.  
  2436.     -- some constants
  2437.     -- this stored proc is for debugging purposes, thus no need for localizing them
  2438.     declare @dbname sysname
  2439.     select @dbname= db_name()
  2440.  
  2441.     declare @missingcolname sysname
  2442.     set @missingcolname= '<Missing column>'
  2443.  
  2444.     declare @anonymousname sysname
  2445.     set @anonymousname= '<Anonymous subscriber>'
  2446.  
  2447.     declare @unknownname sysname
  2448.     set @unknownname= '<Unknown server name>'
  2449.  
  2450.     declare @mergename sysname
  2451.     set @mergename= '<Merge nickname>'
  2452.  
  2453.     declare @nondecreasingversion nvarchar(128)
  2454.     set @nondecreasingversion= 'Problem found: Non-decreasing version.'
  2455.  
  2456.     declare @toohighcolvversion nvarchar(128)
  2457.     set @toohighcolvversion= 'Problem found: Version is higher than highest version in lineage.'
  2458.  
  2459.     declare @naname sysname
  2460.     set @naname= '<n/a>'
  2461.  
  2462.     if @tablename is NULL
  2463.     begin
  2464.         set @tablename= (select top 1 object_name(objid) from sysmergearticles where 
  2465.                             nickname = (select tablenick from MSmerge_contents where rowguid = @rowguid))
  2466.     end
  2467.  
  2468.     if @tablename is NULL
  2469.     begin
  2470.         set @tablename= (select top 1 object_name(objid) from sysmergearticles where 
  2471.                             nickname = (select tablenick from MSmerge_tombstone where rowguid = @rowguid))
  2472.     end
  2473.  
  2474.     -- check whether given table exists
  2475.     if not exists (select * from sysobjects where xtype = 'U' and name = @tablename)
  2476.     begin
  2477.         raiserror (20507, 16, 1, @tablename, @dbname)
  2478.         return 1
  2479.     end
  2480.     else if @ownername is not null
  2481.     begin
  2482.         -- check whether table belongs to the given owner
  2483.         if not exists (select * from sysobjects where xtype = 'U' and name=@tablename and uid = (select uid from sysusers where name = @ownername))
  2484.         begin
  2485.             declare @qualifiedtablename nvarchar(257)
  2486.             select @qualifiedtablename= @ownername + '.' + @dbname
  2487.             raiserror (20507, 16, 1, @qualifiedtablename, @dbname)
  2488.             return 1
  2489.         end
  2490.     end
  2491.  
  2492.     -- get tableid and tablenick from tablename
  2493.     declare @tableid int
  2494.     declare @tablenick int
  2495.     set @tableid= object_id(@tablename)
  2496.     select @tablenick = (select top 1 nickname from sysmergearticles where objid = @tableid)
  2497.     if @tablenick is null
  2498.     begin
  2499.         raiserror (20027, 16, 1, @tablename)
  2500.         return 1
  2501.     end
  2502.  
  2503.     -- check whether there is an entry for this row in either MSmerge_contents or MSmerge_tombstone
  2504.     declare @incontents int
  2505.     declare @lineage varbinary(249)
  2506.     select @lineage= lineage from MSmerge_contents where rowguid = @rowguid
  2507.     if @lineage is not null
  2508.     begin
  2509.         set @incontents= 1
  2510.     end
  2511.     else
  2512.     begin
  2513.         select @lineage= lineage from MSmerge_tombstone where rowguid = @rowguid
  2514.         if @lineage is not null
  2515.         begin
  2516.             set @incontents= 0
  2517.         end
  2518.         else
  2519.         begin
  2520.             raiserror(21511,10,1)
  2521.             return 0
  2522.         end
  2523.     end
  2524.  
  2525.     -- create temporary table for information about lineage and colv entries
  2526.     create table #results (type nchar(7) null, rowversion_table nchar(17) null, server_name sysname null, 
  2527.                             [db_name] sysname null,  db_nickname int not null, colid int null, colname sysname null, 
  2528.                             version int not null, comment nvarchar(255) null, id int identity(1,1) not null) 
  2529.     
  2530.     if lower(@show collate SQL_Latin1_General_CP1_CS_AS) in ('both', 'row')
  2531.     begin
  2532.         -- insert lineage information into temptable
  2533.         insert into #results (db_nickname, version) exec master..xp_showlineage @lineage
  2534.         update #results set type= 'lineage'
  2535.         if (@incontents = 1)
  2536.         begin
  2537.             update #results set rowversion_table = 'MSmerge_contents'
  2538.         end
  2539.         else
  2540.         begin
  2541.             update #results set rowversion_table = 'MSmerge_tombstone'
  2542.         end
  2543.     end
  2544.  
  2545.     if (@incontents = 1) and (lower(@show collate SQL_Latin1_General_CP1_CS_AS) in ('both', 'columns'))
  2546.     begin
  2547.         -- insert colv information into temptable
  2548.         declare @colv varbinary(2048)
  2549.         select @colv= colv1 from MSmerge_contents where rowguid=@rowguid
  2550.         if @colv is not null
  2551.         begin
  2552.             insert into #results (colid, db_nickname, version) exec master..xp_showcolv @colv
  2553.             update #results set type= 'colv' where type is null
  2554.  
  2555.             -- translate colids into column names
  2556.             if (select top 1 missing_col_count from sysmergearticles where nickname = @tablenick) = 0
  2557.             begin
  2558.                 -- no missing cols: position of entries in colv correspond to colid in sysmergearticles
  2559.                 update #results set colname= s.name from syscolumns s where #results.colid = s.colid and s.id = @tableid
  2560.             end
  2561.             else
  2562.             begin
  2563.                 -- missing cols: colv has entries for columns that do not exist in this db
  2564.                 declare @colname sysname
  2565.                 declare @ismissing int
  2566.                 declare @missingsofar int
  2567.                 declare @colid int
  2568.                 declare @missingcols varbinary(128)
  2569.                 select @missingcols= (select top 1 missing_cols from sysmergearticles where nickname = @tablenick)
  2570.                 set @missingsofar= 0
  2571.                 select @colid= (select min(colid) from #results where colname is null and colid is not null)
  2572.                 while @colid is not null
  2573.                 begin
  2574.                     -- is this column missing?
  2575.                     exec @ismissing= sp_MStestbit @missingcols, @colid
  2576.                     if @ismissing <> 0
  2577.                     begin
  2578.                         update #results set colname= @missingcolname, server_name= @naname, [db_name]= @naname
  2579.                                              where colid = @colid
  2580.                         set @missingsofar= @missingsofar + 1
  2581.                     end
  2582.                     else
  2583.                     begin
  2584.                         select @colname= (select name from syscolumns where id = @tableid and colid = (@colid - @missingsofar))
  2585.                         update #results set colname= @colname where colid = @colid
  2586.                     end
  2587.                     
  2588.                     select @colid= (select min(colid) from #results where colname is null and colid is not null)
  2589.                 end
  2590.             end
  2591.         end
  2592.     end
  2593.  
  2594.     -- transform null comment to empty strings
  2595.     update #results set comment= ''
  2596.  
  2597.     -- translate nicknames in temptable into real db names; set server names, too
  2598.     declare @subid uniqueidentifier
  2599.     declare @servername sysname
  2600.     declare @srvid int
  2601.     declare @replnick int
  2602.  
  2603.     update #results set [db_name]= @mergename, server_name= @naname where db_nickname=1
  2604.  
  2605.     select @replnick= (select top 1 db_nickname from #results where [db_name] is null)
  2606.     while @replnick is not null
  2607.     begin
  2608.         select @subid= (select top 1 s.subid
  2609.                             from sysmergesubscriptions s, MSmerge_replinfo r 
  2610.                             where r.repid = s.subid and @replnick = r.replnickname)
  2611.  
  2612.         select @dbname= (select [db_name] from sysmergesubscriptions where subid = @subid)
  2613.         if @dbname is null
  2614.         begin
  2615.             set @dbname=@anonymousname
  2616.             set @servername= @unknownname
  2617.         end
  2618.         else
  2619.         begin
  2620.             select @servername= (select srv.srvname from master..sysservers srv, sysmergesubscriptions sub
  2621.                             where srv.srvid = sub.srvid and sub.subid = @subid)
  2622.         end
  2623.  
  2624.         update #results set [db_name]= @dbname, server_name= @servername 
  2625.                         where db_nickname = @replnick and [db_name] is null
  2626.         select @replnick= (select top 1 db_nickname from #results where [db_name] is null)
  2627.     end
  2628.  
  2629.     -- record increasing lineage versions
  2630.     update #results set comment= @nondecreasingversion 
  2631.             where type = 'lineage' and 
  2632.             exists (select * from #results r where r.version < #results.version and r.id < #results.id)
  2633.  
  2634.     -- record colv versions that are higher than highest lineage version
  2635.     update #results set comment= @toohighcolvversion 
  2636.             where type = 'colv' and 
  2637.             not exists (select version from #results r where type = 'lineage' and r.version >= #results.version)
  2638.     
  2639.     -- deliver results
  2640.     if lower(@show collate SQL_Latin1_General_CP1_CS_AS) in ('both', 'row')
  2641.     begin
  2642.         select server_name, [db_name], db_nickname, version, rowversion_table, comment from #results where type = 'lineage' order by id
  2643.     end
  2644.  
  2645.     if lower(@show collate SQL_Latin1_General_CP1_CS_AS) in ('both', 'columns')
  2646.     begin
  2647.         select server_name, db_name, db_nickname, version, colname, comment from #results where type = 'colv' order by id
  2648.     end
  2649.  
  2650.     drop table #results
  2651.     return 0
  2652. go
  2653. exec dbo.sp_MS_marksystemobject sp_showrowreplicainfo
  2654. go
  2655. grant execute on dbo.sp_showrowreplicainfo to public
  2656. go
  2657.  
  2658.  
  2659. create procedure sp_MSsethighestversion (@artnick int)
  2660. as
  2661.     set nocount on
  2662.     declare @minlineagelength int
  2663.     set @minlineagelength= 8
  2664.  
  2665.     declare @maxversion int
  2666.     declare @maxversiontombstone int
  2667.  
  2668.     set @maxversion= (select max({fn GETMAXVERSION(mc.lineage)}) 
  2669.             from MSmerge_contents as mc inner join #oldgens as og on (mc.generation = og.gen) where
  2670.                 tablenick = @artnick and
  2671.                 lineage is not null and
  2672.                 datalength(lineage) >= @minlineagelength)
  2673.     if @@error<>0 goto Failure
  2674.  
  2675.     set @maxversiontombstone= (select max({fn GETMAXVERSION(mt.lineage)}) 
  2676.             from MSmerge_tombstone as mt inner join #oldgens as og on (mt.generation = og.gen) where
  2677.                 tablenick = @artnick and
  2678.                 lineage is not null and
  2679.                 datalength(lineage) >= @minlineagelength)
  2680.     if @@error<>0 goto Failure
  2681.  
  2682.     if @maxversion is null
  2683.     begin
  2684.         set @maxversion= @maxversiontombstone
  2685.     end
  2686.  
  2687.     if @maxversiontombstone is not null and @maxversiontombstone > @maxversion
  2688.     begin
  2689.         set @maxversion= @maxversiontombstone
  2690.     end
  2691.  
  2692.     if @maxversion is not null
  2693.     begin
  2694.         update sysmergearticles set maxversion_at_cleanup= @maxversion where
  2695.             nickname = @artnick and
  2696.             maxversion_at_cleanup < @maxversion
  2697.         if @@error<>0 goto Failure
  2698.     end
  2699.  
  2700.     return 0
  2701.  
  2702. Failure:
  2703.     return 1
  2704. go
  2705. exec dbo.sp_MS_marksystemobject sp_MSsethighestversion
  2706. go
  2707.  
  2708.  
  2709. create procedure sp_mergemetadataretentioncleanup
  2710.     (@num_genhistory_rows int = 0 output, 
  2711.      @num_contents_rows int = 0 output, 
  2712.      @num_tombstone_rows int = 0 output)
  2713. as
  2714.     declare @maxretention int
  2715.     declare @artnick int
  2716.     declare @gen int
  2717.     declare @retcode smallint
  2718.     declare @bi_objid int
  2719.     declare @cmd nvarchar(200)
  2720.     declare @guidnull uniqueidentifier
  2721.     declare @delbatchsize int
  2722.     declare @delcount int
  2723.        declare @applockname nvarchar(255)
  2724.  
  2725.     set @num_genhistory_rows= 0
  2726.     set @num_contents_rows= 0
  2727.     set @num_tombstone_rows= 0
  2728.  
  2729.     -- Security check
  2730.     if not exists (select * from dbo.sysmergepublications where 1 = {fn ISPALUSER(pubid)})
  2731.     begin    
  2732.         RAISERROR (15247, 11, -1)
  2733.         return (1)
  2734.     end
  2735.  
  2736.     -- if somebody else is already cleaning up in this database, we simply return
  2737.        set @applockname= 'MS_sp_mergemetadataretentioncleanup' + convert(nvarchar(11), db_id())
  2738.     exec @retcode= sp_getapplock @Resource= @applockname, @LockMode= 'Exclusive', @LockOwner= 'Session', @LockTimeout= 0 
  2739.     if @@error <> 0 or @retcode < 0 return (0)
  2740.     
  2741.     set @guidnull= '00000000-0000-0000-0000-000000000000'
  2742.     set @delbatchsize= 5000
  2743.  
  2744.     create table #oldgens (gen int unique clustered)
  2745.  
  2746.     -- iterate over all articles that do not belong to a publication with infinite retention
  2747.     declare article_curs cursor local fast_forward for 
  2748.         select distinct nickname from sysmergearticles where 
  2749.             nickname not in (select distinct a.nickname from sysmergearticles as a inner join sysmergepublications as p on (a.pubid = p.pubid) 
  2750.                                 where isnull(p.retention,0) = 0)
  2751.  
  2752.     open article_curs
  2753.     fetch next from article_curs into @artnick
  2754.  
  2755.     while (@@fetch_status <> -1)
  2756.     begin
  2757.         -- find max retention of all pubs the article belongs to
  2758.         select @maxretention= max(isnull(retention,0)) from sysmergepublications where
  2759.                                 pubid in (select pubid from sysmergearticles where nickname = @artnick)
  2760.         -- add one to make up for maximal possible timezone differences, plus one to compensate for clock inaccuracies
  2761.         set @maxretention= @maxretention + 1
  2762.  
  2763.         delete from #oldgens
  2764.         insert into #oldgens select distinct generation from MSmerge_genhistory where
  2765.                                  art_nick = @artnick and
  2766.                                 guidlocal <> @guidnull and
  2767.                                 coldate < dateadd(day, -@maxretention, getdate())
  2768.  
  2769.         -- go to next article if this one has no stale generations
  2770.         if @@rowcount = 0
  2771.         begin
  2772.             fetch next from article_curs into @artnick
  2773.             continue
  2774.         end
  2775.  
  2776.         -- set highest version in sysmergearticles
  2777.         exec @retcode= sp_MSsethighestversion @artnick= @artnick
  2778.         if @retcode<>0 or @@error<>0 goto Failure
  2779.  
  2780.         -- clean up contents, tombstone, before image (if it exists), genhistory
  2781.         set rowcount @delbatchsize
  2782.         set @delcount= @delbatchsize
  2783.         while @delcount = @delbatchsize
  2784.         begin
  2785.             delete mc from MSmerge_contents as mc inner join #oldgens as og on (mc.generation = og.gen) where mc.tablenick = @artnick
  2786.             set @delcount= @@rowcount
  2787.             set @num_contents_rows= @num_contents_rows + @delcount
  2788.         end
  2789.  
  2790.         set @delcount= @delbatchsize
  2791.         while @delcount = @delbatchsize
  2792.         begin
  2793.             delete mt from MSmerge_tombstone as mt inner join #oldgens as og on (mt.generation = og.gen) where tablenick = @artnick
  2794.             set @delcount= @@rowcount
  2795.             set @num_tombstone_rows= @num_tombstone_rows + @delcount
  2796.         end
  2797.  
  2798.         set @bi_objid= (select top 1 before_image_objid from sysmergearticles where nickname = @artnick)
  2799.         if @bi_objid is not null
  2800.         begin
  2801.             set @cmd= 'delete bi from ' + quotename(object_name(@bi_objid)) + ' as bi inner join #oldgens as og on (bi.generation = og.gen)'
  2802.             set @delcount= @delbatchsize
  2803.             while @delcount = @delbatchsize
  2804.             begin
  2805.                 exec dbo.sp_executesql @cmd
  2806.                 set @delcount= @@rowcount
  2807.             end
  2808.         end
  2809.  
  2810.         set @delcount= @delbatchsize
  2811.         while @delcount = @delbatchsize
  2812.         begin
  2813.             delete gh from MSmerge_genhistory as gh inner join #oldgens as og on (gh.generation = og.gen) where art_nick = @artnick
  2814.             set @delcount= @@rowcount
  2815.             set @num_genhistory_rows= @num_genhistory_rows + @delcount
  2816.         end
  2817.  
  2818.         set rowcount 0
  2819.  
  2820.         -- get next article
  2821.         fetch next from article_curs into @artnick
  2822.     end
  2823.  
  2824.     close article_curs
  2825.     deallocate article_curs
  2826.     drop table #oldgens
  2827.     
  2828.     exec sp_MScleanup_zeroartnick_genhistory @num_genhistory_rows output, @num_contents_rows output
  2829.      
  2830.     exec @retcode= sp_releaseapplock @Resource= @applockname, @LockOwner= 'Session'
  2831.     if @@error <> 0 or @retcode < 0
  2832.         return (1)
  2833.     else
  2834.         return (0)
  2835.  
  2836. Failure:
  2837.     close article_curs
  2838.     deallocate article_curs
  2839.     drop table #oldgens
  2840.     exec sp_releaseapplock @Resource= @applockname, @LockOwner= 'Session'
  2841.     return (1)
  2842.  
  2843. go
  2844. exec dbo.sp_MS_marksystemobject sp_mergemetadataretentioncleanup
  2845. go
  2846. grant execute on dbo.sp_mergemetadataretentioncleanup to public
  2847. go
  2848.  
  2849. raiserror('Creating procedure sp_MSpurgecontentsorphans', 0,1)
  2850. go
  2851. create procedure sp_MSpurgecontentsorphans
  2852. as
  2853.     declare @retcode smallint
  2854.     
  2855.     create table #oldgens (artnick int, gen int)
  2856.     create unique clustered index ucOldgens on #oldgens(artnick, gen)
  2857.  
  2858.     -- find generations that exist in MSmerge_contents but not in MSmerge_genhistory
  2859.     insert into #oldgens (artnick, gen) select distinct tablenick, generation
  2860.             from dbo.MSmerge_contents
  2861.             where generation not in (select distinct generation from dbo.MSmerge_genhistory)
  2862.             
  2863.     exec @retcode = sp_MSdelete_specifiedcontents
  2864.     drop table #oldgens
  2865.     return @retcode
  2866. go
  2867. exec dbo.sp_MS_marksystemobject sp_MSpurgecontentsorphans
  2868. go
  2869.  
  2870.  
  2871. raiserror('Creating procedure sp_MScleanup_zeroartnick_genhistory', 0,1)
  2872. go
  2873. create procedure sp_MScleanup_zeroartnick_genhistory 
  2874.     (@num_genhistory_rows int = 0 output, 
  2875.      @num_contents_rows int = 0 output)
  2876. as
  2877.     declare @retcode smallint
  2878.     declare @maxretention int
  2879.     declare @guidnull uniqueidentifier
  2880.     declare @oldgencount int
  2881.     declare @zeroartnickgencount int
  2882.     
  2883.     -- If there is any publication that has infinite retention, then we 
  2884.     -- should not clean up genhistory rows that have 0 art_nick. This is 
  2885.     -- because the gen could potentially have changes in articles that belong
  2886.     -- to that publication.
  2887.     if exists (select * from sysmergepublications where isnull(retention,0) = 0)
  2888.         return 0
  2889.     
  2890.     -- Now we know we only have publications that have a finite retention period.
  2891.     -- Let us choose the highest retention period across all publications and use
  2892.     -- that when cleaning up generations with 0 art_nick. Again this is because this
  2893.     -- gen could have changes in articles from any of those publications. It is safer
  2894.     -- to be pessimistic.
  2895.     select @maxretention = max(isnull(retention,0)) from sysmergepublications
  2896.     
  2897.     -- add one to make up for maximal possible timezone differences, plus one to compensate for clock inaccuracies
  2898.     set @maxretention= @maxretention + 1
  2899.  
  2900.     create table #oldgens (artnick int, gen int)
  2901.     create unique clustered index ucOldgens on #oldgens(artnick, gen)
  2902.     create table #zeroartnickgens (gen int)
  2903.     create unique clustered index ucZeroartnickgens on #zeroartnickgens(gen)
  2904.     
  2905.     set @guidnull= '00000000-0000-0000-0000-000000000000'
  2906.     
  2907.     insert into #zeroartnickgens (gen) select distinct generation from MSmerge_genhistory where
  2908.                                     art_nick = 0 and
  2909.                                     generation > 1 and
  2910.                                     guidlocal <> @guidnull and
  2911.                                     coldate < dateadd(day, -@maxretention, getdate())
  2912.                                     
  2913.     select @zeroartnickgencount = @@rowcount
  2914.     
  2915.     if (@zeroartnickgencount = 0)
  2916.     begin
  2917.         drop table #oldgens
  2918.         drop table #zeroartnickgens
  2919.         return 0
  2920.     end
  2921.     
  2922.     -- find entries that exist in MSmerge_contents that have art_nick = 0 in MSmerge_genhistory
  2923.     insert into #oldgens (artnick, gen) select distinct tablenick, generation
  2924.             from dbo.MSmerge_contents
  2925.             where generation in (select gen from #zeroartnickgens)
  2926.         
  2927.     select @oldgencount = @@rowcount
  2928.     set @retcode = 0
  2929.     
  2930.     if (@oldgencount > 0)
  2931.     begin
  2932.         exec @retcode = sp_MSdelete_specifiedcontents @num_contents_rows output
  2933.     end
  2934.     
  2935.     if (@@error = 0 and @retcode = 0)
  2936.     begin
  2937.         declare @delcount int
  2938.         declare @delbatchsize int
  2939.         set @delbatchsize= 5000
  2940.  
  2941.         set rowcount @delbatchsize
  2942.         set @delcount= @delbatchsize
  2943.         while @delcount = @delbatchsize
  2944.         begin
  2945.             delete gh from MSmerge_genhistory as gh inner join #zeroartnickgens as zag on (gh.generation = zag.gen) 
  2946.                     where art_nick = 0 
  2947.                     and generation > 1 
  2948.                     and guidlocal <> @guidnull 
  2949.                     and coldate < dateadd(day, -@maxretention, getdate())
  2950.                     
  2951.             set @delcount= @@rowcount
  2952.             set @num_genhistory_rows= @num_genhistory_rows + @delcount
  2953.         end
  2954.  
  2955.         set rowcount 0
  2956.     end
  2957.     
  2958.     drop table #oldgens
  2959.     drop table #zeroartnickgens
  2960.     return @retcode
  2961. go
  2962. exec dbo.sp_MS_marksystemobject sp_MScleanup_zeroartnick_genhistory
  2963. go
  2964. raiserror('Creating procedure sp_MSdelete_specifiedcontents', 0,1)
  2965. go
  2966. create procedure sp_MSdelete_specifiedcontents (@num_contents_rows int = 0 output)
  2967. as
  2968.     declare @retcode smallint
  2969.     -- iterate over articles in the temptable
  2970.     declare @artnick int
  2971.     declare article_curs cursor local fast_forward for 
  2972.         select distinct artnick from #oldgens
  2973.  
  2974.     open article_curs
  2975.     fetch next from article_curs into @artnick
  2976.  
  2977.     while (@@fetch_status <> -1)
  2978.     begin
  2979.         -- if necessary, update highest version in sysmergearticles
  2980.         exec @retcode= sp_MSsethighestversion @artnick= @artnick
  2981.         if @retcode<>0 or @@error<>0 goto Failure
  2982.  
  2983.         -- clean up orphaned rows in MSmerge_contents
  2984.         declare @delcount int
  2985.         declare @delbatchsize int
  2986.         
  2987.         set @delbatchsize= 5000
  2988.         set rowcount @delbatchsize
  2989.         set @delcount= @delbatchsize
  2990.         while @delcount = @delbatchsize
  2991.         begin
  2992.             delete mc from MSmerge_contents as mc inner join #oldgens as og 
  2993.                 on (mc.tablenick = og.artnick and mc.generation = og.gen) 
  2994.                 where mc.tablenick = @artnick
  2995.             set @delcount= @@rowcount
  2996.             set @num_contents_rows = @num_contents_rows + @delcount
  2997.         end
  2998.  
  2999.         -- get next article
  3000.         fetch next from article_curs into @artnick
  3001.     end
  3002.     set rowcount 0
  3003.     
  3004.     close article_curs
  3005.     deallocate article_curs
  3006.     return(0)
  3007.  
  3008. Failure:
  3009.     close article_curs
  3010.     deallocate article_curs
  3011.     return (1)
  3012. go
  3013. exec dbo.sp_MS_marksystemobject sp_MSdelete_specifiedcontents
  3014. go
  3015. dump tran master with no_log
  3016. go
  3017.  
  3018. checkpoint
  3019. go
  3020. set nocount on
  3021. go
  3022.  
  3023. execute dbo.sp_configure 'update',1
  3024. go
  3025. reconfigure with override
  3026. go
  3027.  
  3028. set ANSI_NULLS off
  3029. go
  3030.  
  3031. dump tran master with no_log
  3032. go
  3033.  
  3034. use master
  3035. go
  3036.  
  3037. /* 
  3038. ** Drop the stored procedures in this script using the old dropping SP 
  3039. ** and then drop itself
  3040. */
  3041. if exists (select * from sysobjects
  3042.     where type = 'P '
  3043.             and name = 'sp_MSdrop_rladmin')
  3044. begin
  3045.     drop procedure sp_MSdrop_rladmin
  3046. end
  3047.  
  3048. /*
  3049. ** Create stored procedures to drop the stored procedures
  3050. ** created by this script
  3051. */
  3052.  
  3053. raiserror('Creating procedure sp_MSdrop_rladmin', 0,1)
  3054. GO
  3055. create procedure sp_MSdrop_rladmin
  3056. as
  3057.     if exists (select * from sysobjects
  3058.             where type in ('P ') 
  3059.                 and name = 'sp_MSaddmergepub_snapshot')
  3060.         drop procedure sp_MSaddmergepub_snapshot
  3061.  
  3062.     if exists (select * from sysobjects
  3063.             where type in ('P ') 
  3064.                 and name = 'sp_MSremove_userscript')
  3065.         drop procedure sp_MSremove_userscript
  3066.  
  3067.     if exists (select * from sysobjects
  3068.             where type in ('P ') 
  3069.                 and name = 'sp_MSretrieve_mergepublication')
  3070.         drop procedure sp_MSretrieve_mergepublication
  3071.  
  3072.     if exists (select * from sysobjects
  3073.             where type in ('P ') 
  3074.                 and name = 'sp_MSadjustmergeidentity')
  3075.         drop procedure sp_MSadjustmergeidentity
  3076.  
  3077.     if exists (select * from sysobjects
  3078.             where type in ('P ') 
  3079.                 and name = 'sp_MScheckatpublisher')
  3080.         drop procedure sp_MScheckatpublisher    
  3081.     
  3082.     if exists (select * from sysobjects
  3083.             where type in ('P ') 
  3084.                 and name = 'sp_MSdropmergepub_snapshot')
  3085.         drop procedure sp_MSdropmergepub_snapshot
  3086.     
  3087.     if exists (select * from sysobjects
  3088.             where type = 'P'
  3089.                 and name = 'sp_addmergepublication')
  3090.         drop procedure sp_addmergepublication
  3091.  
  3092.     if exists (select * from sysobjects
  3093.         where type = 'P'
  3094.             and name = 'sp_changemergepublication')
  3095.         drop procedure sp_changemergepublication
  3096.  
  3097.     if exists (select * from sysobjects
  3098.         where type = 'P'
  3099.             and name = 'sp_MSCheckmergereplication')
  3100.         drop procedure sp_MSCheckmergereplication
  3101.  
  3102.     if exists (select * from sysobjects
  3103.             where type = 'P'
  3104.                 and name = 'sp_helpmergepublication')
  3105.         drop procedure sp_helpmergepublication
  3106.  
  3107.     if exists (select * from sysobjects
  3108.             where type = 'P'
  3109.                 and name = 'sp_mergearticlecolumn')
  3110.         drop procedure sp_mergearticlecolumn
  3111.  
  3112.     if exists (select * from sysobjects
  3113.             where type = 'P'
  3114.                 and name = 'sp_helpmergearticlecolumn')
  3115.         drop procedure sp_helpmergearticlecolumn
  3116.  
  3117.     if exists (select * from sysobjects
  3118.             where type = 'P'
  3119.                 and name = 'sp_MSpublicationview')
  3120.         drop procedure sp_MSpublicationview
  3121.  
  3122.      if exists (select * from sysobjects
  3123.                 where type = 'P' and
  3124.                 name = 'sp_reinitmergesubscription')
  3125.         drop procedure sp_reinitmergesubscription
  3126.  
  3127.      if exists (select * from sysobjects
  3128.                 where type = 'P' and
  3129.                 name = 'sp_MSreinitmergepublication')
  3130.         drop procedure sp_MSreinitmergepublication
  3131.      
  3132.  
  3133.     if exists (select * from sysobjects
  3134.             where type = 'P'
  3135.                 and name = 'sp_MScleanup_conflict_table')
  3136.         drop procedure sp_MScleanup_conflict_table
  3137.  
  3138.     if exists (select * from sysobjects
  3139.             where type = 'P'
  3140.                 and name = 'sp_MScleanup_conflict')
  3141.         drop procedure sp_MScleanup_conflict
  3142.  
  3143.     if exists (select * from sysobjects
  3144.         where type = 'P'
  3145.             and name = 'sp_MScleanup_metadata')
  3146.         drop procedure sp_MScleanup_metadata
  3147.  
  3148.     if exists (select * from sysobjects
  3149.         where type = 'P'
  3150.             and name = 'sp_mergecleanupmetadata')
  3151.         drop procedure sp_mergecleanupmetadata
  3152.  
  3153.     if exists (select * from sysobjects
  3154.         where type = 'P'
  3155.             and name = 'sp_MSquiescetriggerson')
  3156.         drop procedure sp_MSquiescetriggerson
  3157.  
  3158.     if exists (select * from sysobjects
  3159.         where type = 'P'
  3160.             and name = 'sp_MSquiescecheck')
  3161.         drop procedure sp_MSquiescecheck
  3162.  
  3163.     if exists (select * from sysobjects
  3164.         where type = 'P'
  3165.             and name = 'sp_MSquiescetriggersoff')
  3166.         drop procedure sp_MSquiescetriggersoff
  3167.  
  3168.     if exists (select * from sysobjects
  3169.         where type = 'P'
  3170.             and name = 'sp_helpmergecleanupwait')
  3171.         drop procedure sp_helpmergecleanupwait
  3172.  
  3173.     if exists (select * from sysobjects
  3174.         where type = 'P'
  3175.             and name = 'sp_mergepreparecleanup')
  3176.         drop procedure sp_mergepreparecleanup
  3177.  
  3178.     if exists (select * from sysobjects
  3179.         where type = 'P'
  3180.             and name = 'sp_MSquiesceforcleanup')
  3181.         drop procedure sp_MSquiesceforcleanup
  3182.  
  3183.     if exists (select * from sysobjects
  3184.         where type = 'P'
  3185.             and name = 'sp_mergecompletecleanup')
  3186.         drop procedure sp_mergecompletecleanup
  3187.  
  3188.     if exists (select * from sysobjects
  3189.         where type = 'P'
  3190.             and name = 'sp_MScompletecleanup')
  3191.         drop procedure sp_MScompletecleanup
  3192.  
  3193.     if exists (select * from sysobjects
  3194.         where type = 'P'
  3195.             and name = 'sp_MSpreparecleanup')
  3196.         drop procedure sp_MSpreparecleanup
  3197.  
  3198.     if exists (select * from sysobjects
  3199.             where type = 'P'
  3200.                 and name = 'sp_MSdrop_expired_mergesubscription')
  3201.         drop procedure sp_MSdrop_expired_mergesubscription
  3202.     
  3203.     if exists (select * from sysobjects
  3204.         where type = 'P'
  3205.             and name = 'sp_dropmergepublication')
  3206.         drop procedure sp_dropmergepublication
  3207.     
  3208.     if exists (select * from sysobjects 
  3209.         where type = 'P'
  3210.             and name = 'sp_MSaddmergeschemaarticle')
  3211.         drop procedure sp_MSaddmergeschemaarticle
  3212.  
  3213.     if exists (select * from sysobjects
  3214.             where type = 'P'
  3215.                 and name = 'sp_addmergearticle')
  3216.         drop procedure sp_addmergearticle
  3217.  
  3218.     if exists (select * from sysobjects 
  3219.         where type = 'P'
  3220.             and name = 'sp_MSchangemergeschemaarticle')
  3221.         drop procedure sp_MSchangemergeschemaarticle
  3222.  
  3223.     if exists (select * from sysobjects
  3224.         where type = 'P'
  3225.             and name = 'sp_changemergearticle')
  3226.         drop procedure sp_changemergearticle
  3227.  
  3228.     if exists (select * from sysobjects
  3229.         where type = 'P'
  3230.             and name = 'sp_MSreinit_hub')
  3231.         drop procedure sp_MSreinit_hub
  3232.  
  3233.     if exists (select * from sysobjects
  3234.         where type = 'P'
  3235.             and name = 'sp_helpmergearticle')
  3236.         drop procedure sp_helpmergearticle
  3237.     
  3238.  
  3239.     if exists (select * from sysobjects
  3240.         where type = 'P'
  3241.             and name = 'sp_dropmergearticle')
  3242.         drop procedure sp_dropmergearticle
  3243.     
  3244.     if exists (select * from sysobjects
  3245.         where type = 'P'
  3246.             and name = 'sp_addmergesubscription')
  3247.         drop procedure sp_addmergesubscription
  3248.     
  3249.     if exists (select * from sysobjects
  3250.         where type = 'P'
  3251.             and name = 'sp_changemergesubscription')
  3252.         drop procedure sp_changemergesubscription
  3253.  
  3254.     if exists (select * from sysobjects
  3255.         where type = 'P'
  3256.             and name = 'sp_helpmergesubscription')
  3257.         drop procedure sp_helpmergesubscription
  3258.  
  3259.     if exists (select * from sysobjects
  3260.         where type = 'P'
  3261.             and name = 'sp_dropmergesubscription')
  3262.         drop procedure sp_dropmergesubscription
  3263.  
  3264.     if exists (select * from sysobjects
  3265.         where type = 'P'
  3266.             and name = 'sp_helpmergefilter')
  3267.         drop procedure sp_helpmergefilter
  3268.  
  3269.     if exists (select * from sysobjects
  3270.         where type = 'P'
  3271.             and name = 'sp_changemergefilter')
  3272.         drop procedure sp_changemergefilter
  3273.     
  3274.     if exists (select * from sysobjects
  3275.         where type = 'P'
  3276.             and name = 'sp_addmergefilter')
  3277.         drop procedure sp_addmergefilter
  3278.     
  3279.     if exists (select * from sysobjects
  3280.         where type = 'P'
  3281.             and name = 'sp_dropmergefilter')
  3282.         drop procedure sp_dropmergefilter
  3283.  
  3284.     if exists (select * from sysobjects
  3285.             where type in ('P ') 
  3286.                 and name = 'sp_MSmergepublishdb')
  3287.         drop procedure sp_MSmergepublishdb
  3288.  
  3289.     if exists (select * from sysobjects
  3290.             where type in ('P ') 
  3291.                 and name = 'sp_helpallowmerge_publication')
  3292.         drop procedure sp_helpallowmerge_publication
  3293.  
  3294.     if exists (select * from sysobjects
  3295.             where type in ('P ') 
  3296.                 and name = 'sp_enumcustomresolvers')
  3297.         drop procedure sp_enumcustomresolvers
  3298.  
  3299.     if exists (select * from sysobjects
  3300.             where type in ('P ') 
  3301.                 and name = 'sp_MSenumpubreferences')
  3302.         drop procedure sp_MSenumpubreferences
  3303.  
  3304.     if exists (select * from sysobjects
  3305.         where type = 'P ' and name = 'sp_MSscript_dri')
  3306.     drop procedure sp_MSscript_dri
  3307.     
  3308.     if exists (select * from sysobjects
  3309.             where type in ('P ') 
  3310.                 and name = 'sp_MSsubsetpublication')
  3311.         drop procedure sp_MSsubsetpublication
  3312.     if exists (select * from sysobjects
  3313.             where type = 'P'
  3314.                 and name = 'sp_generatefilters')
  3315.         drop procedure sp_generatefilters
  3316.     if exists (select * from sysobjects
  3317.             where type = 'P'
  3318.                 and name = 'sp_MSmakejoinfilter')
  3319.         drop procedure sp_MSmakejoinfilter
  3320.     if exists (select * from sysobjects
  3321.             where type = 'P'
  3322.                 and name = 'sp_MSmakeexpandproc')
  3323.         drop procedure sp_MSmakeexpandproc
  3324.     if exists (select * from sysobjects
  3325.             where type = 'P'
  3326.                 and name = 'sp_MSindexcolfrombin')
  3327.         drop procedure sp_MSindexcolfrombin
  3328.  
  3329.     if exists (select * from sysobjects
  3330.             where type = 'P'
  3331.                 and name = 'sp_MShelpvalidationdate')
  3332.         drop procedure sp_MShelpvalidationdate
  3333.  
  3334.     if exists (select * from sysobjects
  3335.                 where type = 'P' and
  3336.                 name = 'sp_helpmergearticleconflicts')
  3337.         drop procedure sp_helpmergearticleconflicts
  3338.  
  3339.     if exists (select * from sysobjects
  3340.                 where type = 'P' and
  3341.                 name = 'sp_MShelpmergeconflictpublications')
  3342.         drop procedure sp_MShelpmergeconflictpublications
  3343.  
  3344.     if exists (select * from sysobjects
  3345.                 where type = 'P' and
  3346.                 name = 'sp_MShelpmergeconflictcounts')
  3347.         drop procedure sp_MShelpmergeconflictcounts
  3348.  
  3349.     if exists (select * from sysobjects
  3350.                 where type = 'P' and
  3351.                 name = 'sp_helpmergeconflictrows')
  3352.         drop procedure sp_helpmergeconflictrows
  3353.  
  3354.     if exists (select * from sysobjects
  3355.                 where type = 'P' and
  3356.                 name = 'sp_helpmergedeleteconflictrows')
  3357.         drop procedure sp_helpmergedeleteconflictrows
  3358.  
  3359.     if exists (select * from sysobjects
  3360.                 where type = 'P' and
  3361.                 name = 'sp_deletemergeconflictrow')
  3362.         drop procedure sp_deletemergeconflictrow
  3363.  
  3364.     if exists (select * from sysobjects
  3365.                 where type = 'P' and
  3366.                 name = 'sp_getmergedeletetype')
  3367.         drop procedure sp_getmergedeletetype
  3368.  
  3369.     if exists (select * from sysobjects
  3370.                 where type = 'P' and
  3371.                 name = 'sp_mergedummyupdate')
  3372.         drop procedure sp_mergedummyupdate
  3373.  
  3374.     if exists (select * from sysobjects
  3375.                 where type = 'P' and
  3376.                 name = 'sp_validatemergepublication')
  3377.         drop procedure sp_validatemergepublication
  3378.  
  3379.     if exists (select * from sysobjects
  3380.                 where type = 'P' and
  3381.                 name = 'sp_validatemergesubscription')
  3382.         drop procedure sp_validatemergesubscription
  3383.  
  3384.     if exists (select * from sysobjects
  3385.                 where type = 'P' and
  3386.                 name = 'sp_addtabletocontents')
  3387.         drop procedure sp_addtabletocontents
  3388.  
  3389.     if exists (select * from sysobjects
  3390.                 where type = 'P' and
  3391.                 name = 'sp_MSaddpubtocontents')
  3392.         drop procedure sp_MSaddpubtocontents
  3393.  
  3394.     if exists (select * from sysobjects
  3395.         where type = 'P' and
  3396.         name = 'sp_MSget_subtypedatasrc')
  3397.         drop procedure sp_MSget_subtypedatasrc
  3398.  
  3399.     if exists (select * from sysobjects
  3400.         where type = 'P'
  3401.             and name = 'sp_addmergealternatepublisher')
  3402.         drop procedure sp_addmergealternatepublisher
  3403.     
  3404.     if exists (select * from sysobjects
  3405.         where type = 'P'
  3406.             and name = 'sp_helpmergealternatepublisher')
  3407.         drop procedure sp_helpmergealternatepublisher
  3408.     
  3409.     if exists (select * from sysobjects
  3410.         where type = 'P'
  3411.             and name = 'sp_dropmergealternatepublisher')
  3412.         drop procedure sp_dropmergealternatepublisher
  3413.     
  3414.  
  3415.     if exists (select * from sysobjects
  3416.         where type = 'P' and 
  3417.         name = 'sp_MScomputemergearticlescreationorder')
  3418.         drop procedure sp_MScomputemergearticlescreationorder
  3419.  
  3420.     if exists (select * from sysobjects
  3421.         where type = 'P' and 
  3422.         name = 'sp_MSclearcolumnbit')
  3423.         drop procedure sp_MSclearcolumnbit
  3424.  
  3425.     if exists (select * from sysobjects
  3426.         where type = 'P' and 
  3427.         name = 'sp_MScomputemergeunresolvedrefs')
  3428.         drop procedure sp_MScomputemergeunresolvedrefs
  3429.  
  3430.     if exists (select * from sysobjects
  3431.         where type = 'P' and 
  3432.         name = 'sp_MSgetpubinfo')
  3433.         drop procedure sp_MSgetpubinfo 
  3434.         
  3435.     if exists (select * from sysobjects
  3436.         where type = 'P' and
  3437.         name = 'sp_MSaddmergedynamicsnapshotjob')
  3438.         drop procedure sp_MSaddmergedynamicsnapshotjob
  3439.  
  3440.     if exists (select * from sysobjects
  3441.         where type = 'P' and
  3442.         name = 'sp_MSpropagateschematorepubs')
  3443.         drop procedure sp_MSpropagateschematorepubs
  3444.     
  3445.     if exists (select * from sysobjects
  3446.         where type = 'P' and
  3447.         name = 'sp_MSdropmergedynamicsnapshotjob')
  3448.         drop procedure sp_MSdropmergedynamicsnapshotjob
  3449.  
  3450.     if exists (select * from sysobjects 
  3451.         where type = 'P' and
  3452.         name = 'sp_MShelpmergedynamicsnapshotjob')
  3453.         drop procedure sp_MShelpmergedynamicsnapshotjob
  3454. go
  3455.  
  3456. exec dbo.sp_MS_marksystemobject sp_MSdrop_rladmin
  3457. go
  3458.  
  3459. EXEC dbo.sp_MSdrop_rladmin
  3460. GO
  3461.  
  3462. raiserror('Creating procedure sp_MSaddmergepub_snapshot', 0,1)
  3463. GO
  3464.  
  3465. CREATE PROCEDURE sp_MSaddmergepub_snapshot (
  3466.     @publication            sysname,    
  3467.     @freqtype               int = 4 ,           /* 4== Daily */
  3468.     @freqinterval           int = 1,            /* Every day */
  3469.     @freqsubtype            int = 4,            /* Sub interval = Minute */
  3470.     @freqsubinterval        int = 5,            /* Every five minutes */
  3471.     @freqrelativeinterval   int = 1, 
  3472.     @freqrecurrencefactor   int = 0, 
  3473.     @activestartdate        int = 0,            /* 12:00 am - 11:59 pm */
  3474.     @activeenddate          int = 99991231 ,    /* No start date */ 
  3475.     @activestarttimeofday   int = 0,        
  3476.     @activeendtimeofday     int = 235959,       /* No end time */               
  3477.     @newtaskid              int = 0 OUTPUT,
  3478.     @snapshot_job_name      nvarchar(100) = null
  3479. ) AS
  3480.  
  3481.     SET NOCOUNT ON
  3482.  
  3483.     /*
  3484.     ** Declarations.
  3485.     */
  3486.     declare @retcode                int
  3487.     declare @distributor            sysname
  3488.     declare @dist_rpcname           sysname
  3489.     declare @distribdb              sysname
  3490.     declare @distproc               nvarchar(300)
  3491.     declare @database               sysname
  3492.     declare @newid                  int
  3493.     declare @fFoundPublication      int
  3494.     declare @task_args              nvarchar(4000)
  3495.     declare @pubid                  uniqueidentifier
  3496.     declare @snapshot_jobid         binary(16)
  3497.     declare @job_existing           bit
  3498.  
  3499.     /*
  3500.     ** Initializations
  3501.     */
  3502.     select @fFoundPublication   = 0 
  3503.     if (@snapshot_job_name is null) or (@snapshot_job_name = N'')
  3504.     begin
  3505.         select @job_existing = 0
  3506.     end
  3507.     else
  3508.     begin
  3509.         select @job_existing = 1
  3510.     end
  3511.  
  3512.     EXEC @retcode = dbo.sp_helpmergepublication @publication, @fFoundPublication output, @pubid output
  3513.  
  3514.     if @@ERROR <> 0 OR @retcode <> 0
  3515.     BEGIN
  3516.         RETURN (1)
  3517.     END
  3518.  
  3519.     /* If the publication does not exist return error */
  3520.     if @fFoundPublication = 0 
  3521.     BEGIN
  3522.         RAISERROR (21040, 11, -1, @publication)
  3523.         RETURN (1)
  3524.     END
  3525.  
  3526.     /* 
  3527.     ** Make sure the publication does not already have a task.
  3528.     */
  3529.     if EXISTS (select * FROM MSmerge_replinfo WHERE repid = @pubid and snapshot_jobid IS NOT NULL)
  3530.     BEGIN
  3531.         RAISERROR (14101, 11, -1, @publication)
  3532.         RETURN(1)
  3533.     END
  3534.  
  3535.     /*
  3536.     ** Get distributor information
  3537.     */
  3538.     EXEC @retcode = dbo.sp_helpdistributor @distributor = @distributor OUTPUT, 
  3539.         @distribdb = @distribdb OUTPUT,
  3540.         @rpcsrvname = @dist_rpcname OUTPUT 
  3541.         if @@error <> 0 OR @retcode <> 0 or @distributor IS NULL OR @distribdb IS NULL
  3542.         BEGIN
  3543.             RAISERROR (14071, 16, -1)
  3544.             RETURN (1)
  3545.         END
  3546.  
  3547.     select @database = DB_NAME()
  3548.  
  3549.     select @task_args = '-Publisher ' + QUOTENAME(@@SERVERNAME)
  3550.     select @task_args = @task_args + ' -PublisherDB ' + QUOTENAME(@database)
  3551.     select @task_args = @task_args + ' -Distributor ' + QUOTENAME(@distributor)
  3552.     select @task_args = @task_args + ' -Publication ' + QUOTENAME(@publication)
  3553.     select @task_args = @task_args + ' -ReplicationType 2'
  3554.     
  3555.     /* 
  3556.     ** Create task on distributor
  3557.     */
  3558.     SELECT @distproc = RTRIM(@dist_rpcname) + '.' + @distribdb + '.dbo.sp_MSadd_snapshot_agent'
  3559.  
  3560.     EXECUTE @retcode = @distproc 
  3561.         @name = @snapshot_job_name,
  3562.         @publisher = @@SERVERNAME,
  3563.         @publisher_db = @database,
  3564.         @publication = @publication,  
  3565.         @publication_type = 2,          -- Merge type
  3566.         @local_job = 1,  
  3567.         @freqtype = @freqtype, 
  3568.         @freqinterval = @freqinterval, 
  3569.         @freqsubtype = @freqsubtype, 
  3570.         @freqsubinterval = @freqsubinterval, 
  3571.         @freqrelativeinterval = @freqrelativeinterval, 
  3572.         @freqrecurrencefactor = @freqrecurrencefactor, 
  3573.         @activestartdate = @activestartdate,
  3574.         @activeenddate =@activeenddate ,         
  3575.         @activestarttimeofday = @activestarttimeofday,         
  3576.         @activeendtimeofday = @activeendtimeofday,     
  3577.         @command = @task_args, 
  3578.         @snapshot_jobid = @snapshot_jobid OUTPUT,
  3579.         @job_existing = @job_existing 
  3580.  
  3581.    if @@ERROR <> 0 or @retcode <> 0
  3582.         RETURN(1)
  3583.     
  3584.     SELECT @newtaskid = 1
  3585.  
  3586.     UPDATE MSmerge_replinfo set snapshot_jobid = @snapshot_jobid WHERE repid = @pubid
  3587.  
  3588.     if @@ERROR <> 0 
  3589.         RETURN(1)
  3590.             
  3591.     return (0)
  3592. GO
  3593. exec dbo.sp_MS_marksystemobject sp_MSaddmergepub_snapshot
  3594. go
  3595.  
  3596.  
  3597. GO
  3598.  
  3599. raiserror('Creating procedure sp_MSdropmergepub_snapshot', 0,1)
  3600. GO
  3601.  
  3602. CREATE PROCEDURE sp_MSdropmergepub_snapshot (
  3603.     @publication sysname,
  3604.     @ignore_distributor bit = 0
  3605. ) AS
  3606.  
  3607.     SET NOCOUNT ON
  3608.  
  3609.     /*
  3610.     ** Declarations.
  3611.     */
  3612.     declare @retcode            int
  3613.     declare @distributor        sysname
  3614.     declare @distproc           nvarchar(300)
  3615.     declare @snapshot_jobid     binary(16)
  3616.     declare @fFoundPublication  int
  3617.     declare @pubid              uniqueidentifier
  3618.     declare @distribdb          sysname
  3619.  
  3620.     /*
  3621.     ** Initializations
  3622.     */
  3623.     select @fFoundPublication = 0
  3624.  
  3625.     /* validate the publication */
  3626.     /* If the publication is  not exist found return error */
  3627.     EXEC @retcode = dbo.sp_helpmergepublication @publication, @fFoundPublication output, @pubid output
  3628.     if @@ERROR <> 0 OR @fFoundPublication = 0 OR @retcode <> 0
  3629.     BEGIN
  3630.         RETURN (1)
  3631.     END
  3632.  
  3633.     /*
  3634.     ** Get taskid. Make sure the snapshot_jobid is not NULL only before using MAX
  3635.     ** Otherwise there will be a warnning.
  3636.     */
  3637.     select @snapshot_jobid = max(snapshot_jobid) FROM MSmerge_replinfo WHERE repid = @pubid
  3638.     
  3639.     if (@snapshot_jobid IS NOT NULL)        
  3640.     begin
  3641.  
  3642.     /*
  3643.     ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
  3644.     */
  3645.     if @ignore_distributor = 0
  3646.         begin
  3647.             /*
  3648.             ** Get distributor information
  3649.             */
  3650.             EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
  3651.                 @distribdb = @distribdb OUTPUT
  3652.                 if @@error <> 0 OR @retcode <> 0
  3653.                 BEGIN
  3654.                     RAISERROR (14071, 16, -1)
  3655.                     RETURN (1)
  3656.                 END
  3657.  
  3658.             /*
  3659.             ** Delete sync agent of Publication.
  3660.             */
  3661.             declare @dbname sysname
  3662.             set @dbname = DB_NAME()
  3663.             SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + '.dbo.sp_MSdrop_snapshot_agent'
  3664.             EXECUTE @retcode = @distproc 
  3665.                 @publisher = @@SERVERNAME,
  3666.                 @publisher_db = @dbname,
  3667.                 @publication = @publication
  3668.  
  3669.             IF @@ERROR <> 0 or @retcode <> 0
  3670.                 RETURN(1)
  3671.         end
  3672.  
  3673.  
  3674.         /* Update publication's taskid */
  3675.         UPDATE MSmerge_replinfo set snapshot_jobid = NULL WHERE repid = @pubid
  3676.         IF @@ERROR <> 0
  3677.             BEGIN
  3678.             RAISERROR (20072, 16, -1)
  3679.             RETURN (1)
  3680.             END
  3681.  
  3682.     end
  3683.             
  3684.     return (0)      
  3685. GO 
  3686. exec dbo.sp_MS_marksystemobject sp_MSdropmergepub_snapshot 
  3687. go
  3688.  
  3689.  
  3690. raiserror('Creating procedure sp_MScheckatpublisher', 0,1)
  3691. GO
  3692.  
  3693. create procedure sp_MScheckatpublisher
  3694.     @pubid                  uniqueidentifier
  3695.     AS
  3696.     -- this routine will be called by sp_addmergearticle, sp_changemergearticle
  3697.     declare @db_name        sysname
  3698.     
  3699.     select @db_name =db_name from sysmergesubscriptions
  3700.         where (pubid=@pubid) and (subid=@pubid) 
  3701.         IF @db_name <> db_name() 
  3702.             RETURN 1
  3703.         ELSE 
  3704.             RETURN 0
  3705.             
  3706. go
  3707. exec dbo.sp_MS_marksystemobject sp_MScheckatpublisher
  3708. go
  3709.          
  3710. raiserror('Creating procedure sp_MSaddmergeschemaarticle', 0,1)
  3711. GO
  3712.  
  3713. create procedure sp_MSaddmergeschemaarticle
  3714.     @pubid                              uniqueidentifier,    
  3715.     @article                            sysname,
  3716.     @source_object                      sysname,
  3717.     @type                               tinyint, 
  3718.     @description                        nvarchar(255),
  3719.     @status                             nvarchar(10),   
  3720.     @pre_creation_command               int,
  3721.     @creation_script                    nvarchar(255),
  3722.     @source_owner                       sysname,
  3723.     @destination_owner                  sysname,    
  3724.     @schema_option                      binary(8),
  3725.     @destination_object                 sysname,
  3726.     @qualified_name                     nvarchar(270),
  3727.     @publication                        sysname, 
  3728.     @snapshot_ready                     int,
  3729.     @force_invalidate_snapshot          bit
  3730. AS
  3731.     SET NOCOUNT ON
  3732.  
  3733.     DECLARE @retcode              int
  3734.     DECLARE @objid                int    
  3735.     DECLARE @artid                uniqueidentifier
  3736.     DECLARE @bInTran              bit
  3737.     DECLARE @valid_schema_options int
  3738.     DECLARE @bump_to_80           bit
  3739.         
  3740.     SELECT @bInTran = 0
  3741.     SELECT @objid = OBJECT_ID(@qualified_name)
  3742.     -- We are going to bump the compatibility level anyway
  3743.     -- since we are adding schema only articles
  3744.     SELECT @bump_to_80 = 1
  3745.     RAISERROR(21391, 10, -1, @publication)
  3746.  
  3747.     /*
  3748.     ** Parameter check: Source object type must match
  3749.     ** specified article type.
  3750.     **
  3751.     */
  3752.     -- Type has to be one of 0x20, 0x40, or 0x80 by the time 
  3753.     -- this sp is called
  3754.     IF @type = 0x20
  3755.     BEGIN
  3756.         IF NOT EXISTS (SELECT * 
  3757.                          FROM sysobjects
  3758.                         WHERE id = @objid
  3759.                           AND xtype = 'P ')
  3760.         BEGIN
  3761.             RAISERROR(21219, 16, -1)
  3762.             RETURN (1)
  3763.         END 
  3764.                         
  3765.     END
  3766.     ELSE IF @type = 0x40
  3767.     BEGIN
  3768.         IF NOT EXISTS (SELECT *
  3769.                          FROM sysobjects
  3770.                         WHERE id = @objid
  3771.                           AND xtype = 'V ')
  3772.         BEGIN
  3773.             RAISERROR(21221, 16, -1)
  3774.             RETURN (1)
  3775.         END
  3776.     END
  3777.     ELSE IF @type = 0x80
  3778.     BEGIN
  3779.         IF NOT EXISTS (SELECT *
  3780.                          FROM sysobjects
  3781.                         WHERE id = @objid
  3782.                           AND xtype IN ('FN','TF', 'IF'))
  3783.         BEGIN
  3784.             RAISERROR(21228, 16, -1)
  3785.             RETURN (1)
  3786.         END
  3787.     END
  3788.  
  3789.  
  3790.     /*
  3791.     ** Parameter check: @schema_option
  3792.     ** For proc and func schema only articles, schema_option can 
  3793.     ** only contain the options
  3794.     ** 0x0000000000000001, 0x0000000000002000
  3795.     ** for schema only articles except view. View articles can contain 
  3796.     ** the options 0x0000000000000010, 0x0000000000000020, and 0x0000000000000100 
  3797.     ** in addition to the aforementioned options.
  3798.     */
  3799.     IF @type = 0x40
  3800.     BEGIN
  3801.  
  3802.         -- Since only the lower 32 bits of @schema_option are
  3803.         -- currently used, the following check is sufficient.
  3804.         -- Note that @schema_option should have been padded out already.
  3805.         DECLARE @schema_option_lodword int
  3806.         SELECT @valid_schema_options = 0x2151
  3807.         SELECT @schema_option_lodword = fn_replgetbinary8lodword(@schema_option)
  3808.         IF (@schema_option_lodword & ~@valid_schema_options) <> 0
  3809.         BEGIN
  3810.             RAISERROR (21229, 16, -1)
  3811.             RETURN (1)
  3812.         END
  3813.     END
  3814.     ELSE IF @schema_option NOT IN (0x0000000000000000,
  3815.                                    0x0000000000000001,
  3816.                                    0x0000000000002000,
  3817.                                    0x0000000000002001)
  3818.     BEGIN
  3819.         RAISERROR (21222, 16, -1)
  3820.         RETURN (1)
  3821.     END 
  3822.  
  3823.  
  3824.     /*
  3825.     ** Parameter check: @pre_creation_command must be
  3826.     ** 'drop' (id = 1) or 'none' (id = 0)
  3827.     */
  3828.     IF @pre_creation_command NOT IN (0, 1)
  3829.     BEGIN
  3830.         RAISERROR(21223, 16, -1)
  3831.         RETURN (1)
  3832.     END
  3833.  
  3834.     -- Reuse @artid from articles publishing the same object so we can
  3835.     -- link these articles together during the reinit/republishing scenario 
  3836.  
  3837.     SELECT @artid = NULL
  3838.     SELECT @artid = artid 
  3839.       FROM sysmergeschemaarticles 
  3840.      WHERE objid = @objid
  3841.  
  3842.     IF @artid IS NULL
  3843.     BEGIN
  3844.         SELECT @artid = newid()
  3845.     END
  3846.  
  3847.     BEGIN TRAN
  3848.     SAVE TRANSACTION sp_MSaddmergeschemaarticle
  3849.     SELECT @bInTran = 1
  3850.  
  3851.     IF @snapshot_ready > 0
  3852.     BEGIN
  3853.         IF @force_invalidate_snapshot = 0
  3854.         BEGIN
  3855.             RAISERROR(21364, 16, -1, @article)
  3856.             GOTO FAILURE
  3857.         END
  3858.         RAISERROR(21360, 10, -1, @publication)
  3859.         SELECT @bump_to_80 = 1
  3860.         UPDATE sysmergepublications 
  3861.            SET snapshot_ready=2 
  3862.          WHERE pubid=@pubid
  3863.         IF @@ERROR<>0
  3864.             GOTO FAILURE
  3865.     END
  3866.  
  3867.     INSERT sysmergeschemaarticles (name, type, objid, artid, description,
  3868.         pre_creation_command, pubid, status, creation_script, schema_option,
  3869.         destination_object, destination_owner)
  3870.     VALUES (@article, @type, @objid, @artid, @description, @pre_creation_command,
  3871.         @pubid, 1, @creation_script, @schema_option, @destination_object,
  3872.         @destination_owner)
  3873.  
  3874.     IF @@ERROR <> 0
  3875.         GOTO FAILURE
  3876.  
  3877.     -- Mark the source object as a replication object so
  3878.     -- user cannot drop it 
  3879.     UPDATE sysobjects SET replinfo = replinfo | 0x00000200 WHERE id = @objid   
  3880.     
  3881.     IF @@ERROR <> 0
  3882.         GOTO FAILURE
  3883.  
  3884.     IF @bump_to_80=1
  3885.     BEGIN
  3886.         EXEC @retcode = sp_MSBumpupCompLevel @pubid, 40
  3887.         IF @@ERROR<>0 or @retcode<>0
  3888.             GOTO FAILURE
  3889.     END
  3890.  
  3891.     COMMIT TRANSACTION 
  3892.     
  3893.     RETURN (0)
  3894.  
  3895. FAILURE:
  3896.  
  3897.     IF @bInTran = 1
  3898.     BEGIN
  3899.         ROLLBACK TRANSACTION sp_MSaddmergeschemaarticle
  3900.         COMMIT TRANSACTION
  3901.     END    
  3902.     RETURN (1)
  3903. go
  3904.  
  3905. exec dbo.sp_MS_marksystemobject sp_MSaddmergeschemaarticle
  3906.  
  3907.  
  3908. raiserror('Creating procedure sp_addmergearticle', 0,1)
  3909. GO
  3910.  
  3911. create procedure sp_addmergearticle
  3912.     @publication            sysname,                            /* publication name */
  3913.     @article                sysname,                            /* article name */
  3914.     @source_object          sysname,                            /* source object name */
  3915.     @type                   sysname = 'table',                  /* article type */
  3916.     @description            nvarchar(255)= NULL,                /* article description */
  3917.     @column_tracking        nvarchar(10) = 'false',             /* column level tracking */
  3918.     @status                 nvarchar(10) = 'unsynced',          /* unsynced, active */
  3919.     @pre_creation_cmd       nvarchar(10) = 'drop',              /* 'none', 'drop', 'delete', 'truncate' */
  3920.     @creation_script        nvarchar(255)= NULL,                /* article schema script */
  3921.     @schema_option          varbinary(8)   = NULL,              /* article schema creation options */
  3922.     @subset_filterclause    nvarchar(1000) = '',                /* filter clause */
  3923.     @article_resolver       nvarchar(255)= NULL,                 /* custom resolver for article */
  3924.     @resolver_info          nvarchar(255) = NULL,                /* custom resolver info */
  3925.     @source_owner           sysname = NULL,
  3926.     @destination_owner        sysname = NULL,
  3927.     @vertical_partition        nvarchar(5) = 'FALSE',                /* vertical partitioning or not */
  3928.     @auto_identity_range    nvarchar(5)    = 'FALSE',                /* set it to false for now - change is possible */
  3929.     @pub_identity_range        bigint    = NULL,
  3930.     @identity_range            bigint = NULL,
  3931.     @threshold                int    = NULL,
  3932.     @verify_resolver_signature         int = 0,                    /* 0=do not verify signature, 1=verify that signature is from trusted source, more values may be added later */
  3933.     @destination_object             sysname = @source_object,
  3934.     @allow_interactive_resolver        nvarchar(5) = 'false',        /* whether article allows interactive resolution or not */
  3935.     @fast_multicol_updateproc        nvarchar(5) = 'true',        /* whether update proc should update multiple columns in one update statement or not. if 0, then separate update issued for each column changed. */
  3936.     @check_permissions        int = 0, /* bitmap where 0x00 for nochecks, 0x01 for insert check, 0x2 for update check, 0x4 for delete check */
  3937.     @force_invalidate_snapshot bit = 0, /* Force invalidate existing snapshot */
  3938.     @published_in_tran_pub nvarchar(5) = 'false' /* Indicates that this articles could be published in a transactional publication as well */
  3939.     AS
  3940.  
  3941.     set nocount on
  3942.  
  3943.     /*
  3944.     ** Declarations.
  3945.     */
  3946.     declare @max_range                bigint
  3947.     declare @publisher                sysname
  3948.     declare @publisher_db            sysname
  3949.     declare @already_published        bit
  3950.     declare @identity_so_far        bigint
  3951.     declare @ver_partition            int
  3952.     declare @sp_resolver            sysname
  3953.     declare @num_columns            smallint
  3954.     declare @pubid                  uniqueidentifier                /* Publication id */
  3955.     declare @db                     sysname
  3956.     declare @identity_support        int
  3957.     declare @object                 sysname
  3958.     declare @owner                  sysname
  3959.     declare @retcode                int
  3960.     declare @objid                  int
  3961.     declare @sync_objid             int
  3962.     declare @typeid                 smallint
  3963.     declare @nickname               int
  3964.     declare @merge_pub_object_bit int
  3965.     declare @column_tracking_id     int
  3966.     declare @cmd                    nvarchar(255)
  3967.     declare @statusid               tinyint --1: inactive; 2: active; 5:new_inactive 6:new_active
  3968.     declare @next_seed                bigint
  3969.     declare @precmdid               int
  3970.     declare @resolver_clsid         nvarchar(50)
  3971.     declare @resolver_clsid_old     nvarchar(50)
  3972.     declare @tablenick              int
  3973.     declare @artid                  uniqueidentifier
  3974.     declare @i                        int
  3975.     declare @max_identity            bigint
  3976.     declare @colname                sysname
  3977.     declare @indid                    int
  3978.     declare @pkkey                    sysname
  3979.     declare @distributor            sysname
  3980.     declare @distribdb              sysname
  3981.     declare @distproc               nvarchar(300)
  3982.     declare @dbname                 sysname
  3983.     declare @replinfo               int
  3984.     declare @db_name                sysname
  3985.     declare @subset                 int
  3986.     declare @is_publisher            int
  3987.     declare @row_size               int
  3988.     declare @sp_name                sysname
  3989.     declare @sp_owner                sysname
  3990.     declare @qualified_name         nvarchar(270)
  3991.     declare @snapshot_ready         tinyint
  3992.     declare @sync_mode                tinyint
  3993.     declare @allow_interactive_bit    bit
  3994.     declare @fast_multicol_updateproc_bit bit
  3995.     declare @published_in_tran_pub_bit bit
  3996.     declare @additive_resolver        sysname
  3997.     declare @average_resolver        sysname
  3998.     declare @mindate_resolver        sysname
  3999.     declare @needs_pickup            bit
  4000.     declare @maxdate_resolver        sysname
  4001.     declare @minimum_resolver        sysname
  4002.     declare @maximum_resolver        sysname
  4003.     declare @mergetxt_resolver        sysname
  4004.     declare @pricolumn_resolver        sysname
  4005.     declare @xtype                    int
  4006.     declare @xprec                    int
  4007.     declare @initial_setting        bit
  4008.     declare @bump_to_80                bit
  4009.     declare @gen                     int
  4010.     declare @replnick                 int
  4011.     declare @genguid                 uniqueidentifier
  4012.     declare @guidnull                 uniqueidentifier
  4013.     declare @dt                     datetime
  4014.     
  4015.     /* make sure current database is enabled for merge replication */
  4016.     exec @retcode=dbo.sp_MSCheckmergereplication
  4017.     if @@ERROR<>0 or @retcode<>0
  4018.         return (1)
  4019.  
  4020.     /*
  4021.     ** Initializations 
  4022.     */
  4023.     set @guidnull = '00000000-0000-0000-0000-000000000000'
  4024.     select @is_publisher = 0
  4025.     select @initial_setting = 0
  4026.     select @needs_pickup = 0
  4027.     select @bump_to_80 = 0
  4028.     select @already_published = 0
  4029.     select @publisher = @@SERVERNAME
  4030.     select @publisher_db = db_name()
  4031.     select @max_identity    = NULL
  4032.     select @next_seed        = NULL
  4033.     select @statusid        = 0
  4034.     select @resolver_clsid  = NULL
  4035.     select @subset          = 1     /* Const: publication type 'subset' */
  4036.     select @merge_pub_object_bit    = 128
  4037.     select @db_name    = db_name()
  4038.     select @sp_resolver         = 'Microsoft SQLServer Stored Procedure Resolver'
  4039.     select @additive_resolver     = 'Microsoft SQL Server Additive Conflict Resolver'
  4040.     select @average_resolver     = 'Microsoft SQL Server Averaging Conflict Resolver'
  4041.     select @minimum_resolver     = 'Microsoft SQL Server Minimum Conflict Resolver'
  4042.     select @maximum_resolver     = 'Microsoft SQL Server Maximum Conflict Resolver'
  4043.     select @mindate_resolver     = 'Microsoft SQL Server DATETIME (Earlier Wins) Conflict Resolver'
  4044.     select @maxdate_resolver     = 'Microsoft SQL Server DATETIME (Later Wins) Conflict Resolver'
  4045.     select @mergetxt_resolver     = 'Microsoft SQL Server Merge Text Columns Conflict Resolver'
  4046.     select @pricolumn_resolver     = 'Microsoft SQL Server Priority Column Resolver'
  4047.  
  4048.     if @source_owner is NULL
  4049.         begin
  4050.             select @source_owner = user_name(uid) from sysobjects where id = object_id(@source_object)
  4051.             if @source_owner is NULL  
  4052.                 begin
  4053.                     raiserror (14027, 11, -1, @source_object)
  4054.                     return (1)
  4055.                 end
  4056.         end
  4057.     select @qualified_name = QUOTENAME(@source_owner) + '.' + QUOTENAME(@source_object)
  4058.  
  4059.     if @subset_filterclause <> '' and @subset_filterclause is not NULL
  4060.     begin
  4061.     /* check the validity of subset_filterclause */
  4062.     exec ('declare @test int select @test=1 from ' + @qualified_name + ' where (1=2) and ' + @subset_filterclause)
  4063.     if @@ERROR<>0
  4064.         begin
  4065.             raiserror(21256, 16, -1, @subset_filterclause, @article)
  4066.             return (1)
  4067.         end
  4068.     end
  4069.     if @destination_owner is NULL
  4070.         select @destination_owner = 'dbo'
  4071.     
  4072.     /*
  4073.     ** Security Check
  4074.     */
  4075.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  4076.     IF @@ERROR <> 0 or @retcode <> 0
  4077.         return (1)
  4078.  
  4079.     /*
  4080.     ** Pad out the specified schema option to the left
  4081.     */
  4082.     select @schema_option = fn_replprepadbinary8(@schema_option)
  4083.  
  4084.     /*
  4085.     ** Parameter Check: @publication.
  4086.     ** The @publication id cannot be NULL and must conform to the rules
  4087.     ** for identifiers.
  4088.     */   
  4089.         
  4090.     if @publication is NULL
  4091.         begin
  4092.             raiserror (14043, 16, -1, '@publication')
  4093.             return (1)
  4094.         end
  4095.  
  4096.     select @pubid = pubid, @snapshot_ready = snapshot_ready, @sync_mode=sync_mode from sysmergepublications 
  4097.         where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
  4098.     if @pubid is NULL
  4099.         begin
  4100.             raiserror (20026, 16, -1, @publication)
  4101.             return (1)
  4102.         end
  4103.  
  4104.     if lower(@article)='all'
  4105.         begin
  4106.             raiserror(21401, 16, -1)
  4107.             return (1)
  4108.         end
  4109.  
  4110.     /*
  4111.     ** Parameter Check: @type
  4112.     ** If the article is added as a 'indexed view schema only' article,
  4113.     ** make sure that the source object is a schema-bound view.
  4114.     ** Conversely, a schema-bound view cannot be published as a 
  4115.     ** 'view schema only' article.
  4116.     */
  4117.     select @type = lower(@type collate SQL_Latin1_General_CP1_CS_AS)
  4118.  
  4119.     if @type = N'indexed view schema only' and objectproperty(object_id(@qualified_name), 'IsSchemaBound') <> 1
  4120.     begin
  4121.         raiserror (21277, 11, -1, @qualified_name)        
  4122.         return (1)    
  4123.     end
  4124.     else if @type = N'view schema only' and objectproperty(object_id(@qualified_name), 'IsSchemaBound') = 1
  4125.     begin
  4126.         raiserror (21275, 11, -1, @qualified_name)
  4127.         return (1)
  4128.     end
  4129.  
  4130.     /*
  4131.     ** Only publisher can call sp_addmergearticle
  4132.     */
  4133.     EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
  4134.     IF @@ERROR <> 0 or @retcode <>  0
  4135.         BEGIN
  4136.             RAISERROR (20073, 16, -1)
  4137.             RETURN (1)
  4138.         END
  4139.         
  4140.     /*
  4141.     ** Parameter Check: @article.
  4142.     ** Check to see that the @article is local, that it conforms
  4143.     ** to the rules for identifiers, and that it is a table, and not
  4144.     ** a view or another database object.
  4145.     */
  4146.  
  4147.     if @article is NULL
  4148.         begin
  4149.             raiserror (20045, 16, -1)
  4150.             return (1)
  4151.         end
  4152.  
  4153.     exec @retcode = dbo.sp_MSreplcheck_name @article
  4154.     if @@ERROR <> 0 or @retcode <> 0
  4155.         return(1)
  4156.         
  4157.  
  4158.     /*
  4159.     ** Set the precmdid.  The default type is 'drop'.
  4160.     **
  4161.     **      @precmdid   pre_creation_cmd
  4162.     **      =========   ================
  4163.     **            0     none
  4164.     **            1     drop
  4165.     **            2     delete
  4166.     **            3     truncate
  4167.     */
  4168.     IF LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('none', 'drop', 'delete', 'truncate')
  4169.        BEGIN
  4170.           RAISERROR (14061, 16, -1)
  4171.           RETURN (1)
  4172.        END
  4173.  
  4174.     /*
  4175.     ** Determine the integer value for the pre_creation_cmd.
  4176.     */
  4177.     IF LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS) = 'none'
  4178.        select @precmdid = 0
  4179.     ELSE IF LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
  4180.        select @precmdid = 1
  4181.     ELSE IF LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS) = 'delete'
  4182.        select @precmdid = 2
  4183.     ELSE IF LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS) = 'truncate'
  4184.        select @precmdid = 3
  4185.  
  4186.  
  4187.     /*
  4188.     ** Set the typeid.  The default type is table.  It can 
  4189.     ** be one of following.
  4190.     **
  4191.     **      @typeid     type
  4192.     **      =======     ========
  4193.     **         0xa      table
  4194.     **        0x20      proc schema only
  4195.     **        0x40      view schema only
  4196.     **        0x80      func schema only
  4197.     **        0x40      indexed view schema only (overloaded)
  4198.     */        
  4199.  
  4200.     IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('table', 'proc schema only', 'view schema only', 'func schema only', 'indexed view schema only')
  4201.        BEGIN
  4202.             RAISERROR (20074, 16, -1)
  4203.             RETURN (1)
  4204.        END
  4205.  
  4206.     IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'table'
  4207.     BEGIN
  4208.        SET @typeid = 0x0a
  4209.     END
  4210.     ELSE IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'proc schema only'
  4211.     BEGIN
  4212.        SET @typeid = 0x20 
  4213.     END
  4214.     ELSE IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'view schema only'
  4215.     BEGIN
  4216.        SET @typeid = 0x40
  4217.     END
  4218.     ELSE IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'indexed view schema only'
  4219.     BEGIN
  4220.        SET @typeid = 0x40
  4221.     END
  4222.     ELSE IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'func schema only'
  4223.     BEGIN
  4224.        SET @typeid = 0x80
  4225.     END
  4226.  
  4227.     select @sync_objid = OBJECT_ID(@qualified_name)
  4228.     if @sync_objid is NULL
  4229.         begin
  4230.             raiserror (14027, 11, -1, @qualified_name)
  4231.             return (1)
  4232.         end
  4233.  
  4234.  
  4235.     if @typeid in (0x20,0x40,0x80)
  4236.     begin
  4237.         if exists (select * from syscomments
  4238.                     where id = @sync_objid
  4239.                       and encrypted = 1)
  4240.         begin
  4241.             raiserror(21004, 16, -1, @source_object)
  4242.             return 1
  4243.         end
  4244.     end
  4245.  
  4246.     /*
  4247.     ** Parameter Check:  @article, @publication.
  4248.     ** Check if the article already exists in this publication.
  4249.     */
  4250.  
  4251.     IF EXISTS (SELECT *
  4252.                  FROM sysmergeextendedarticlesview
  4253.                 WHERE pubid = @pubid
  4254.                   AND name = @article)
  4255.         BEGIN
  4256.             raiserror (21292, 16, -1, @source_object)
  4257.             RETURN (1)
  4258.         END
  4259.         
  4260.     /*
  4261.     ** At this point, all common parameter validations 
  4262.     ** for table and schema only articles have been 
  4263.     ** performed, so branch out here to handle schema
  4264.     ** only articles as a special case.
  4265.     */
  4266.     
  4267.     IF @typeid in (0x20, 0x40, 0x80)
  4268.     BEGIN
  4269.     
  4270.         IF @destination_object IS NULL OR @destination_object = N''
  4271.         BEGIN
  4272.             SELECT @destination_object = @source_object
  4273.         END
  4274.     
  4275.         IF @schema_option IS NULL
  4276.         BEGIN
  4277.             SELECT @schema_option = 0x0000000000000001
  4278.         END
  4279.         EXEC @retcode = dbo.sp_MSaddmergeschemaarticle 
  4280.             @pubid = @pubid,
  4281.             @article = @article,
  4282.             @source_object = @source_object,
  4283.             @type = @typeid,
  4284.             @description = @description,
  4285.             @status = @status,
  4286.             @pre_creation_command = @precmdid,
  4287.             @creation_script = @creation_script,
  4288.             @source_owner = @source_owner,
  4289.             @destination_owner = @destination_owner,
  4290.             @schema_option = @schema_option,
  4291.             @destination_object = @destination_object,
  4292.             @qualified_name = @qualified_name,   
  4293.             @publication = @publication,
  4294.             @snapshot_ready = @snapshot_ready,
  4295.             @force_invalidate_snapshot = @force_invalidate_snapshot
  4296.         
  4297.        RETURN (@retcode)
  4298.     END
  4299.  
  4300.     IF @schema_option IS NULL
  4301.     BEGIN
  4302.         SELECT @schema_option = 0x000000000000CFF1
  4303.     END
  4304.  
  4305.     /*
  4306.     ** If scheme option contains collation or extended properties, 
  4307.     ** bump up the compatibility-level
  4308.     */    
  4309.     -- Since only the lower 32 bits of @schema_option are 
  4310.     -- used, the following check is sufficient. Note that @schema_option is
  4311.     -- already padded out to the left at the beginning of this procedure.
  4312.     declare @schema_option_lodword int
  4313.     declare @xprop_schema_option int
  4314.     declare @collation_schema_option int
  4315.     select @xprop_schema_option = 0x00002000
  4316.     select @collation_schema_option = 0x00001000
  4317.     select @schema_option_lodword = fn_replgetbinary8lodword(@schema_option)
  4318.     if (@schema_option_lodword & @collation_schema_option) <> 0
  4319.     begin    
  4320.         raiserror(21389, 10, -1, @publication)
  4321.         select @bump_to_80 = 1
  4322.     end
  4323.     if (@schema_option_lodword & @xprop_schema_option) <> 0
  4324.     begin   
  4325.         raiserror(21390, 10, -1, @publication)
  4326.         select @bump_to_80 = 1
  4327.     end
  4328.  
  4329.     /*
  4330.     ** Merge table articles does not really support destination object. It has the same value as source
  4331.     */
  4332.     select @destination_object = @source_object
  4333.  
  4334. /*
  4335.     select @row_size=sum(length) from syscolumns where id=OBJECT_ID(@qualified_name)
  4336.     if @row_size>6000 
  4337.         begin
  4338.             RAISERROR (21062, 16, -1, @qualified_name)  
  4339.             -- RETURN (1)
  4340.         end
  4341. */
  4342.     IF LOWER(@vertical_partition collate SQL_Latin1_General_CP1_CS_AS) = 'false'
  4343.         begin
  4344.             select @ver_partition = 0
  4345.         end
  4346.     else
  4347.         begin            
  4348.             select @ver_partition = 1
  4349.         end
  4350.     select @num_columns=count(*) from syscolumns where id = object_id(@qualified_name)
  4351.  
  4352.     if @num_columns > 246 and LOWER(@vertical_partition collate SQL_Latin1_General_CP1_CS_AS) = 'false'
  4353.         begin
  4354.             RAISERROR (20068, 16, -1, @qualified_name, 246)
  4355.             RETURN (1)
  4356.         end
  4357.  
  4358.     /*
  4359.     **  Get the id of the @qualified_name
  4360.     */
  4361.     select @objid = id, @replinfo = replinfo from sysobjects where id = OBJECT_ID(@qualified_name)
  4362.     if @objid is NULL
  4363.         begin
  4364.             raiserror (14027, 11, -1, @qualified_name)
  4365.             return (1)
  4366.         end
  4367.  
  4368.     /*
  4369.     ** If current publication contains a non-sync subscription, all articles to be added in it
  4370.     ** has to contain a rowguidcol.
  4371.     */
  4372.     if exists (select * from sysmergesubscriptions where pubid = @pubid and sync_type = 2)
  4373.         begin
  4374.             if not exists (select * from syscolumns c 
  4375.                 where c.id=@objid and ColumnProperty(c.id, c.name, 'isrowguidcol') = 1)
  4376.                 begin
  4377.                     raiserror(20086 , 16, -1, @publication)
  4378.                     return (1)
  4379.                 end
  4380.         end
  4381.  
  4382.     /*
  4383.     ** If you want to have identity support, @range and threshold can not be NULL
  4384.     */
  4385.     if LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'true' and (@identity_range is NULL or @threshold is NULL or @pub_identity_range is NULL)
  4386.         begin
  4387.             raiserror(21193, 16, -1)
  4388.             return (1)
  4389.         end
  4390.  
  4391.     if LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'false' and (@identity_range is not NULL or @threshold is not NULL or @pub_identity_range is not NULL)
  4392.         begin
  4393.             raiserror(21282, 16, -1)
  4394.             return (1)
  4395.         end
  4396.  
  4397.     if @threshold<0 OR @threshold>100
  4398.         begin
  4399.             raiserror(21241, 16, -1)
  4400.             return (1)
  4401.         end
  4402.  
  4403.     if LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  4404.         begin
  4405.             select @identity_support = 1
  4406.             if OBJECTPROPERTY(@objid, 'tablehasidentity') <> 1
  4407.             begin
  4408.                 raiserror(21194, 16, -1)
  4409.                 return (1)
  4410.             end
  4411.         
  4412.             if @pub_identity_range <= 1 or @identity_range <= 1
  4413.             begin
  4414.                 raiserror(21232, 16 ,-1)
  4415.                 return 1
  4416.             end
  4417.  
  4418.             select @xtype=xtype, @xprec=xprec from syscolumns where id=@objid and columnproperty(id, name, 'IsIdentity')=1
  4419.             select @max_range =
  4420.                     case @xtype when 52 then power((convert(bigint,2)), 8*2-1) - 1 --smallint 
  4421.                         when 48 then power((convert(bigint,2)), 8-1) - 1          --tinyint
  4422.                         when 56 then power((convert(bigint,2)), 8*4-1) - 1          --int
  4423.                         when 127 then power((convert(bigint,2)), 62) - 1 + power((convert(bigint,2)), 62)      --bigint
  4424.                          else
  4425.                             power((convert(bigint,2)), 62) -1 + power((convert(bigint,2)), 62)  -- defaulted to bigint
  4426.                     end
  4427.  
  4428.             if (@xtype=108 or @xtype=106) and @xprec<18
  4429.                 select @max_range = power((convert(bigint,10)), (@xprec+1)) - 1
  4430.         
  4431.             if @pub_identity_range * 2 + @identity_range > (@max_range - IDENT_CURRENT(@source_object))
  4432.                 begin
  4433.                     raiserror(21290, 16, -1)
  4434.                     return (1)
  4435.                 end
  4436.         end
  4437.     else
  4438.         select @identity_support = 0            
  4439.  
  4440.  
  4441.     /*
  4442.     ** Make sure that the table name specified is a table and not a view.
  4443.     */
  4444.  
  4445.     if NOT exists (select * from sysobjects
  4446.         where id = (select OBJECT_ID(@qualified_name)) AND type = 'U')
  4447.         begin
  4448.             raiserror (20074, 16, -1)
  4449.             return (1)
  4450.         end
  4451.  
  4452.     /*
  4453.     ** If the table contains one more columns of type bigint or sql_variant, 
  4454.     ** and the publication is not of type native mode, we bump up the backward 
  4455.     ** compatibility level.
  4456.     */
  4457.     if @sync_mode=0 and EXISTS (SELECT * FROM syscolumns c WHERE c.id = @sync_objid
  4458.                 AND (type_name(c.xtype) = 'bigint' or type_name(c.xtype) = 'sql_variant'))
  4459.     begin
  4460.         raiserror(21357, 10, -1, @publication)
  4461.         select    @bump_to_80 = 1
  4462.     end
  4463.  
  4464.     /*
  4465.     ** 7.0 subscribers do not like data type 'timestamp'
  4466.     */
  4467.     if EXISTS (select * from syscolumns where id=@sync_objid and type_name(xtype) ='timestamp')
  4468.     begin
  4469.         raiserror(21358, 10, -1, @publication)
  4470.         select @bump_to_80 = 1
  4471.     end
  4472.         
  4473.     /*
  4474.     ** Validate the column tracking
  4475.     */
  4476.     if @column_tracking IS NULL OR LOWER(@column_tracking collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  4477.         BEGIN
  4478.             RAISERROR (14148, 16, -1, '@column_tracking')
  4479.             RETURN (1)
  4480.         END
  4481.     if LOWER(@column_tracking collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
  4482.         SET @column_tracking_id = 1
  4483.     else 
  4484.         SET @column_tracking_id = 0
  4485.  
  4486.     if @column_tracking_id=0 and @sync_mode = 1 and @ver_partition = 1
  4487.         begin
  4488.             RAISERROR (21244, 16, -1)
  4489.             RETURN (1)
  4490.         end
  4491.  
  4492.        /*
  4493.     ** Parameter Check: @allow_interactive_resolver  
  4494.     */
  4495.     if LOWER(@allow_interactive_resolver collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  4496.         BEGIN
  4497.             RAISERROR (14148, 16, -1, '@allow_interactive_resolver')
  4498.             RETURN (1)
  4499.         END
  4500.     if LOWER(@allow_interactive_resolver collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  4501.         set @allow_interactive_bit = 1
  4502.     else 
  4503.         set @allow_interactive_bit = 0
  4504.  
  4505.     /*
  4506.     ** Parameter Check: @published_in_tran_pub  
  4507.     */
  4508.     if LOWER(@published_in_tran_pub collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  4509.         BEGIN
  4510.             RAISERROR (14148, 16, -1, '@published_in_tran_pub')
  4511.             RETURN (1)
  4512.         END
  4513.     if LOWER(@published_in_tran_pub collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  4514.         set @published_in_tran_pub_bit = 1
  4515.     else 
  4516.         set @published_in_tran_pub_bit = 0
  4517.  
  4518.     /*
  4519.     ** Parameter Check: @fast_multicol_updateproc  
  4520.     */
  4521.     if LOWER(@fast_multicol_updateproc collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  4522.         BEGIN
  4523.             RAISERROR (14148, 16, -1, '@fast_multicol_updateproc')
  4524.             RETURN (1)
  4525.         END
  4526.     if LOWER(@fast_multicol_updateproc collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  4527.         set @fast_multicol_updateproc_bit = 1
  4528.     else 
  4529.         set @fast_multicol_updateproc_bit = 0
  4530.  
  4531.     /*
  4532.     ** Get the pubid.
  4533.     */
  4534.     SELECT @pubid = pubid FROM sysmergepublications 
  4535.         WHERE name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
  4536.     if @pubid is NULL
  4537.         begin
  4538.             raiserror (20026, 11, -1, @publication)
  4539.             return (1)
  4540.         end
  4541.  
  4542.     execute @retcode = dbo.sp_MSgetreplnick @pubid = @pubid, @nickname = @nickname output
  4543.     if (@@error <> 0) or @retcode <> 0 or @nickname IS NULL 
  4544.         begin
  4545.         RAISERROR (14055, 11, -1)
  4546.         RETURN(1)
  4547.         end                 
  4548.  
  4549.     /*
  4550.     ** Get distribution server information for remote RPC call.
  4551.     */
  4552.     EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
  4553.                        @distribdb   = @distribdb OUTPUT
  4554.     IF @@ERROR <> 0 or @retcode <> 0 or @distributor is NULL
  4555.     BEGIN
  4556.         RAISERROR (21337, 16, -1)
  4557.         RETURN (1)
  4558.     END
  4559.  
  4560.     /*
  4561.     ** Validate the article resolver
  4562.     */
  4563.     if @article_resolver IS NOT NULL
  4564.         begin
  4565.             if @article_resolver = 'default' OR @article_resolver = ''
  4566.                 begin
  4567.                     select @article_resolver = NULL
  4568.                     select @resolver_clsid = NULL
  4569.                 end                 
  4570.             else
  4571.                 begin
  4572.                     /*
  4573.                     ** Get the distributor info
  4574.                     */
  4575.                     select @distproc = RTRIM(@distributor) + '.master.dbo.xp_regread'
  4576.                     EXECUTE @retcode = @distproc 'HKEY_LOCAL_MACHINE',
  4577.                                   'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\ArticleResolver',
  4578.                                   @article_resolver,
  4579.                                   @param = @resolver_clsid  OUTPUT
  4580.  
  4581.                     IF @retcode <> 0 or @resolver_clsid IS NULL
  4582.                         BEGIN
  4583.                           RAISERROR (20020, 16, -1)
  4584.                           RETURN (1)
  4585.                         END
  4586.                 end
  4587.         end
  4588.  
  4589.     /*
  4590.     ** If article resolver is 'SP resolver', make sure that resolver_info refers to an SP or XP;
  4591.     ** Also make sure it is stored with owner qualification
  4592.     */
  4593.     if  @article_resolver = @sp_resolver
  4594.         begin
  4595.             if not exists (select * from sysobjects where id = object_id(@resolver_info) and ( type = 'P' or type = 'X'))
  4596.                 begin
  4597.                     raiserror(21343, 16, -1, @resolver_info)
  4598.                     return (1)
  4599.                 end
  4600.                 
  4601.             select @sp_name = name, @sp_owner=user_name(uid) from sysobjects where id = object_id(@resolver_info)
  4602.             select @resolver_info = QUOTENAME(@sp_owner) + '.' + QUOTENAME(@sp_name) 
  4603.         end
  4604.  
  4605.     /* The following resolvers expect the @resolver_info to be NON NULL */
  4606.     if  @article_resolver = @sp_resolver or 
  4607.         @article_resolver = @additive_resolver or
  4608.         @article_resolver = @average_resolver or
  4609.         @article_resolver = @minimum_resolver or
  4610.         @article_resolver = @maximum_resolver or
  4611.         @article_resolver = @mindate_resolver or
  4612.         @article_resolver = @maxdate_resolver or
  4613.         @article_resolver = @mergetxt_resolver or
  4614.         @article_resolver = @pricolumn_resolver
  4615.         begin
  4616.             if @resolver_info IS NULL 
  4617.                 begin
  4618.                     RAISERROR (21301, 16, -1, @article_resolver)
  4619.                     return (1)
  4620.                 end
  4621.         end
  4622.     /*
  4623.     ** If article resolver uses column names, make sure that resolver_info refers to a valid column.
  4624.     */
  4625.     if  @article_resolver = @pricolumn_resolver or
  4626.         @article_resolver = @additive_resolver or
  4627.         @article_resolver = @average_resolver or
  4628.         @article_resolver = @minimum_resolver or
  4629.         @article_resolver = @maximum_resolver
  4630.         begin
  4631.             if not exists (select * from syscolumns where id = @objid and name=@resolver_info)
  4632.                 begin
  4633.                     RAISERROR (21501, 16, -1, @article_resolver)
  4634.                     return (1)
  4635.                 end
  4636.         end
  4637.     /*
  4638.     ** If article resolver is 'mindate/maxdate resolver', make sure that resolver_info refers to a column that is of datatype 'datetime' or smalldatetime
  4639.     */
  4640.     if  @article_resolver = @mindate_resolver or
  4641.         @article_resolver = @maxdate_resolver
  4642.         begin
  4643.             if not exists (select * from syscolumns where id = @objid and name=@resolver_info and type_name(xtype)='datetime' or type_name(xtype) = 'smalldatetime' )
  4644.                 begin
  4645.                     RAISERROR (21302, 16, -1, @article_resolver)
  4646.                     return (1)
  4647.                 end
  4648.         end
  4649.  
  4650.     /* The following resolvers expect the article to be column tracked - warn that the default resolver will be used */
  4651.     if  @article_resolver = @additive_resolver or
  4652.         @article_resolver = @average_resolver or
  4653.         @article_resolver = @mergetxt_resolver
  4654.         begin
  4655.             if @column_tracking_id = 0
  4656.                 begin
  4657.                     RAISERROR (21303, 10, -1, @article, @article_resolver)
  4658.                 end
  4659.                 
  4660.         end
  4661.  
  4662.     if @resolver_info IS NOT NULL and @article_resolver IS NULL
  4663.         begin
  4664.             RAISERROR (21300, 10, -1, @article)
  4665.             set @resolver_info = NULL
  4666.         end
  4667.  
  4668.     /* Make sure that coltracking option matches */
  4669.     if exists (select * from sysmergearticles where objid = @objid and
  4670.             identity_support <> @identity_support)
  4671.         begin
  4672.             raiserror (21240, 16, -1, @source_object)
  4673.             return (1)
  4674.         end
  4675.  
  4676.     -- Do not allow the table to be published by both merge and queued tran
  4677.     if exists (select * from sysobjects where name = 'syspublications')
  4678.     begin
  4679.         if exists (select * from syspublications p, sysarticles a where 
  4680.             p.allow_queued_tran = 1 and
  4681.             p.pubid = a.pubid and
  4682.             a.objid = @objid)
  4683.         begin
  4684.             declare @obj_name sysname
  4685.             select @obj_name = object_name(@objid)
  4686.             raiserror(21266, 16, -1, @obj_name)
  4687.             return (1)
  4688.         end
  4689.     end
  4690.  
  4691.     if exists (select * from sysmergearticles where objid=@objid and pubid in(select pubid from sysmergepublications where UPPER(publisher)=UPPER(@publisher) 
  4692.                 and publisher_db=@publisher_db))
  4693.     select @already_published = 1
  4694.  
  4695.     if @already_published = 1 and LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  4696.     begin
  4697.         raiserror(21359, 10, -1, @publication)
  4698.         select @bump_to_80 = 1
  4699.         if exists (select * from MSrepl_identity_range where objid=@objid and 
  4700.             ((pub_range<>@pub_identity_range) or (range <> @identity_range) or (threshold <> @threshold)))
  4701.             begin
  4702.                 raiserror(21291, 16, -1)
  4703.                 return (1)
  4704.             end
  4705.     end
  4706.     
  4707.     /*
  4708.     **  Add article to sysmergearticles and update sysobjects category bit.
  4709.     */
  4710.     begin tran
  4711.     save TRAN sp_addmergearticle
  4712.  
  4713.     /*
  4714.     ** We used to prevent an article from being added to a publication whose snapshot
  4715.     ** has been run already. Now we change this so that it is acceptable by doing reinit.
  4716.     */
  4717.         if @snapshot_ready > 0 
  4718.         begin
  4719.             if @force_invalidate_snapshot = 0
  4720.             begin
  4721.                 raiserror(21364, 16, -1, @article)
  4722.                 goto FAILURE
  4723.             end
  4724.             update sysmergepublications set snapshot_ready=2 where pubid=@pubid
  4725.             if @@ERROR<>0
  4726.                 goto FAILURE
  4727.         end
  4728.  
  4729.     /* 
  4730.     ** article status 5 or 6 means there is at least one new article after snapshot is ready
  4731.     ** hence all articles added after that point will be new articles as well, regardless of snapshot_ready value.
  4732.     */
  4733.         if @snapshot_ready>0 or exists (select * from sysmergearticles where pubid=@pubid and (status=5 or status=6))
  4734.         begin
  4735.             select @needs_pickup=1
  4736.         end
  4737.  
  4738.  
  4739.         /*
  4740.         ** the case when @already_publisher=1 has been handled outside of the transaction
  4741.         */
  4742.         if LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'true' and @already_published = 0
  4743.         begin
  4744.             -- Set the range to negtive if incr of the identity is negtive
  4745.             if IDENT_INCR(@source_object) < 0
  4746.             begin
  4747.                 select @pub_identity_range = -1 * @pub_identity_range;
  4748.                 select @identity_range = -1 * @identity_range;
  4749.             end
  4750.             raiserror(21359, 10, -1, @publication)
  4751.             select @bump_to_80 = 1
  4752.             select @next_seed = next_seed, @max_identity=max_identity from MSrepl_identity_range where objid=@objid
  4753.             select @identity_so_far = 0
  4754.             if @next_seed is NULL
  4755.             begin
  4756.                 select @initial_setting = 1 -- adjust for existing rows, only for original publisher
  4757.                 select @is_publisher= 1 --original publisher
  4758.                 select @identity_so_far = IDENT_CURRENT(@source_object)
  4759.                 if @identity_so_far is NULL
  4760.                     begin
  4761.                         select @next_seed = IDENT_SEED(@source_object)
  4762.                         select @identity_so_far = @next_seed
  4763.                     end
  4764.                 else
  4765.                     select @next_seed = @identity_so_far
  4766.  
  4767.                 -- use boundary values by cutting off odds,    
  4768.                 -- and always give publisher side one more range to allow for existing rows.                
  4769.  
  4770.                 /* To avoid div by zero errors, error out if pub_range is 0 */
  4771.                 if @pub_identity_range = 0
  4772.                     begin
  4773.                         goto FAILURE
  4774.                     end
  4775.                 select @next_seed = (@next_seed/@pub_identity_range) * @pub_identity_range 
  4776.  
  4777.                 -- to compensate publisher side an extra range in case it loses some slots by rounding up.
  4778.                 -- which only happens when the identity incremental is a positive value
  4779.  
  4780.                 if (((@pub_identity_range > 0) and (@identity_so_far > @next_seed))
  4781.                     OR
  4782.                     ((@pub_identity_range < 0) and (@identity_so_far < @next_seed))) --to make it symmetric both directions
  4783.                     
  4784.                     select @next_seed = @next_seed + @pub_identity_range
  4785.                     
  4786.                 select @max_identity = @max_range --max range decided by data type of identity column
  4787.                 
  4788.                 insert MSrepl_identity_range(objid, next_seed, pub_range, range, max_identity, threshold, current_max)
  4789.                     values (@objid,@next_seed + @pub_identity_range, @pub_identity_range, @identity_range, @max_identity, @threshold, @next_seed + @pub_identity_range)
  4790.             end    
  4791.             else
  4792.             begin
  4793.                 select @is_publisher=2 -- republisher
  4794.                 update MSrepl_identity_range set current_max = @next_seed + @pub_identity_range,
  4795.                                                  pub_range = @pub_identity_range,
  4796.                                                  threshold= @threshold,
  4797.                                                  range = @identity_range
  4798.                     where objid=@objid
  4799.                 if @@ERROR<>0
  4800.                     goto FAILURE
  4801.             end
  4802.                 
  4803.             select @distproc = RTRIM(@distributor) + '.' + @distribdb + '.dbo.sp_MSinsert_identity'
  4804.             SELECT @dbname =  DB_NAME()
  4805.             exec @retcode = @distproc @publisher = @publisher,
  4806.                                       @publisher_db = @publisher_db,
  4807.                                       @identity_support=@identity_support,
  4808.                                       @tablename=@source_object,
  4809.                                       @pub_identity_range = @pub_identity_range,
  4810.                                       @identity_range =@identity_range,
  4811.                                       @threshold =@threshold,
  4812.                                       @next_seed = @next_seed,
  4813.                                       @max_identity=@max_identity
  4814.             if @retcode<>0 or @@ERROR<>0
  4815.                 goto FAILURE
  4816.                 
  4817.             /* This is to change identity column to 'not for replication' if not having been so already */
  4818.             select @colname=NULL
  4819.             select @colname = name from syscolumns  where
  4820.                  id = @objid and
  4821.                  colstat & 0x0001 <> 0 and -- is identity
  4822.                  colstat & 0x0008 = 0 -- No 'not for repl' property
  4823.             if @colname is not null
  4824.             begin
  4825.                 exec @retcode  = dbo.sp_replupdateschema @source_object
  4826.                 -- Mark 'not for repl'
  4827.                 update syscolumns set colstat = colstat | 0x0008 where
  4828.                     id = @objid and name = @colname
  4829.                 -- Single to refresh the object cache.
  4830.                 exec @retcode  = dbo.sp_replupdateschema @source_object
  4831.                 IF @@ERROR <> 0 OR @retcode <> 0
  4832.                     goto FAILURE
  4833.             end
  4834.  
  4835.         end
  4836.  
  4837.         select @artid = artid from sysmergearticles where objid = @objid
  4838.         select @statusid = 1  /*default status is inactive */
  4839.  
  4840.         if @artid is NULL
  4841.             begin
  4842.                 set @artid = newid()
  4843.                 if @@ERROR <> 0
  4844.                     goto FAILURE
  4845.                 execute @retcode = dbo.sp_MSgentablenickname @tablenick output, @nickname, @objid
  4846.                 if @@ERROR <> 0 OR @retcode <> 0
  4847.                     goto FAILURE
  4848.             end
  4849.         /* Clone the article properties if article has already been published (in a different pub) */
  4850.         else
  4851.             begin
  4852.             /*
  4853.             ** Parameter Check:  @article, @publication.
  4854.             ** Check if the table already exists in this publication.
  4855.             */
  4856.             if exists (select * from sysmergearticles
  4857.                 where pubid = @pubid AND artid = @artid)
  4858.                 begin
  4859.                     raiserror (21292, 16, -1, @source_object)
  4860.                     goto FAILURE
  4861.                 end
  4862.             
  4863.             /* Make sure that coltracking option matches */
  4864.             if exists (select * from sysmergearticles where artid = @artid and
  4865.                          column_tracking <> @column_tracking_id)
  4866.                 begin
  4867.                     raiserror (20030, 16, -1, @article)
  4868.                     goto FAILURE
  4869.                 end
  4870.  
  4871.             /* Reuse the article nickname if article has already been published (in a different pub)*/
  4872.             select @tablenick = nickname from sysmergearticles where artid = @artid
  4873.             if @tablenick IS NULL
  4874.                 goto FAILURE
  4875.                 
  4876.             /* Make sure that @resolver_clsid matches the existing resolver_clsid */
  4877.             select @resolver_clsid_old = resolver_clsid from sysmergearticles where artid = @artid 
  4878.             if ((@resolver_clsid IS NULL AND @resolver_clsid_old IS NOT NULL) OR
  4879.                 (@resolver_clsid IS NOT NULL AND @resolver_clsid_old IS NULL) OR
  4880.                 (@resolver_clsid IS NOT NULL AND @resolver_clsid_old IS NOT NULL AND @resolver_clsid_old <> @resolver_clsid))
  4881.                 begin
  4882.                     raiserror (20037, 16, -1, @article)
  4883.                     goto FAILURE
  4884.                 end
  4885.  
  4886.             /* Insert to articles, copying some stuff from other article row */
  4887.             insert into sysmergearticles (name, type, objid, sync_objid, artid, description,
  4888.                     pre_creation_command, pubid, nickname, column_tracking, status,
  4889.                     creation_script, article_resolver,
  4890.                     resolver_clsid, schema_option, 
  4891.                     destination_object, destination_owner, subset_filterclause, view_type, resolver_info, gen_cur, 
  4892.                     missing_cols, missing_col_count, excluded_cols, excluded_col_count, identity_support,
  4893.                     before_image_objid, before_view_objid, verify_resolver_signature, allow_interactive_resolver, 
  4894.                     fast_multicol_updateproc, check_permissions, published_in_tran_pub)
  4895.                 -- use top 1, distinct could return more than one matching row if status different on partitioned articles
  4896.                 select top 1 @article, type, objid, @sync_objid, @artid, @description, @precmdid,
  4897.                     @pubid, nickname, column_tracking, @statusid, @creation_script,
  4898.                     article_resolver, resolver_clsid, @schema_option, @destination_object, @destination_owner, @subset_filterclause, 
  4899.                     0, resolver_info, gen_cur, 0x00, 0, 0x00,0, identity_support,
  4900.                     before_image_objid, before_view_objid, verify_resolver_signature, allow_interactive_resolver, 
  4901.                     fast_multicol_updateproc, check_permissions, published_in_tran_pub
  4902.                     from sysmergearticles where artid = @artid
  4903.  
  4904.             /* Jump to end of transaction  */
  4905.             goto DONE_TRAN
  4906.             end
  4907.  
  4908.         /* Add the specific GUID based replication columns to sysmergearticles */
  4909.         insert sysmergearticles (name, objid, sync_objid, artid, type, description, pubid, nickname, 
  4910.                 column_tracking, status, schema_option, pre_creation_command, destination_object, destination_owner, 
  4911.                 article_resolver, resolver_clsid, subset_filterclause, view_type, resolver_info, columns,
  4912.                 missing_cols, missing_col_count, excluded_cols, excluded_col_count, identity_support,
  4913.                 before_image_objid, before_view_objid, verify_resolver_signature, creation_script, allow_interactive_resolver, 
  4914.                 fast_multicol_updateproc, check_permissions, published_in_tran_pub)
  4915.         values (@article, @objid, @sync_objid, @artid, @typeid, @description, @pubid, @tablenick, 
  4916.                 @column_tracking_id, @statusid, @schema_option, @precmdid, @destination_object, @destination_owner, 
  4917.                 @article_resolver, @resolver_clsid, @subset_filterclause, 0, @resolver_info, NULL,
  4918.                  0x00, 0, 0x00,0, @identity_support, NULL, NULL, @verify_resolver_signature, @creation_script, @allow_interactive_bit, 
  4919.                  @fast_multicol_updateproc_bit, @check_permissions, @published_in_tran_pub_bit)
  4920.         if @@ERROR <> 0
  4921.             goto FAILURE
  4922.  
  4923.         exec @retcode = dbo.sp_replupdateschema @qualified_name
  4924.         if @@ERROR <> 0 or @retcode <> 0
  4925.             goto FAILURE
  4926.         update sysobjects set replinfo = (replinfo | @merge_pub_object_bit) where id = @objid
  4927.         if @@ERROR <> 0
  4928.             goto FAILURE
  4929.  
  4930.         /* set up the article's gen-cur */
  4931.         set @genguid = newid()
  4932.         set @dt = getdate()
  4933.  
  4934.         exec @retcode=sp_MSgetreplnick @nickname = @replnick out
  4935.         if @retcode<>0 or @@error<>0 
  4936.             goto FAILURE
  4937.  
  4938.         /*
  4939.         ** If there are no zero generation tombstones or rows, add a dummy row in there. 
  4940.         */
  4941.            if not exists (select * from MSmerge_genhistory)
  4942.             begin
  4943.             begin tran
  4944.                insert into MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) values
  4945.                 (@genguid, @genguid, 1, 0, @replnick, @dt)
  4946.             if (@@error <> 0)
  4947.                 begin
  4948.                 goto FAILURE
  4949.                 end    
  4950.             commit tran
  4951.             end
  4952.  
  4953.         /* Make a generation and update the article's gen_cur */
  4954.         select @gen = max(gen_cur) from sysmergearticles (updlock holdlock) where nickname = @tablenick and gen_cur is not null
  4955.         if @gen is null
  4956.             begin
  4957.             set @genguid = newid()
  4958.             set @dt = getdate()
  4959.             insert into MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) 
  4960.                 select @genguid, @guidnull, COALESCE(1 + max(generation), 1), @tablenick, @replnick, @dt from MSmerge_genhistory (updlock)
  4961.             if (@@error <> 0)
  4962.                 goto FAILURE
  4963.             select @gen =  generation from MSmerge_genhistory where guidsrc = @genguid
  4964.             update sysmergearticles set gen_cur = @gen where nickname = @tablenick
  4965.             if (@@error <> 0)
  4966.                 goto FAILURE
  4967.             end
  4968.  
  4969.         /* If the article status is active then prepare the article for merge replication */
  4970.         if @status = 'active'
  4971.             begin
  4972.                 /* Get a holdlock on the underlying table */
  4973.                 select @cmd = 'select * into #tab1 from '
  4974.                 select @cmd = @cmd + @qualified_name 
  4975.                 select @cmd = @cmd + '(TABLOCK HOLDLOCK) where 1 = 2 '
  4976.                 execute(@cmd)
  4977.  
  4978.                 /* Add the guid column to the user table */
  4979.                 execute @retcode = dbo.sp_MSaddguidcolumn @source_owner, @source_object
  4980.                 if @@ERROR <> 0 OR  @retcode <> 0  -- NOTE: new change
  4981.                     goto FAILURE
  4982.  
  4983.                 /* Create an index on the rowguid column in the user table */
  4984.                 execute @retcode = dbo.sp_MSaddguidindex @publication, @source_owner, @source_object
  4985.                 if @@ERROR <> 0 OR @retcode <> 0
  4986.                     goto FAILURE
  4987.  
  4988.                 /* Create the merge triggers on the base table */
  4989.                 execute @retcode = dbo.sp_MSaddmergetriggers @qualified_name, NULL, @column_tracking_id
  4990.                 if @@ERROR <> 0 OR @retcode <> 0
  4991.                     goto FAILURE 
  4992.  
  4993.                 /* Create the merge insert/update stored procedures for the base table */
  4994.                 execute @retcode = dbo.sp_MSsetartprocs @publication, @article
  4995.                 if @@ERROR <> 0 OR @retcode <> 0
  4996.                     goto FAILURE
  4997.  
  4998.                 /* Set the article status to be active so that Snapshot does not do this again */
  4999.                 select @statusid = 2 /* Active article */
  5000.                 update sysmergearticles set status = @statusid where artid = @artid
  5001.                 if @@ERROR <> 0 
  5002.                     goto FAILURE
  5003.             end
  5004.         
  5005. DONE_TRAN:                
  5006.             /* identity range control is row level. So one the one is needed for each table */
  5007.             if @identity_support=1 and @already_published=0
  5008.             begin
  5009.  
  5010.                 exec @retcode = sp_MSreseed @objid=@objid,
  5011.                                         @next_seed=@next_seed,
  5012.                                         @range = @pub_identity_range,
  5013.                                         @is_publisher=@is_publisher,
  5014.                                         @check_only = 1,
  5015.                                         @initial_setting = @initial_setting,
  5016.                                         @bound_value = @identity_so_far
  5017.                 if @@ERROR<>0 or @retcode<>0
  5018.                         goto FAILURE
  5019.             end
  5020.  
  5021.     /*
  5022.     ** Set all bits to '1' in the columns column to include all columns.
  5023.     */
  5024.  
  5025.         IF @ver_partition = 0 --meanning no vertical partition needed.
  5026.         BEGIN
  5027.             EXECUTE @retcode  = dbo.sp_mergearticlecolumn @publication=@publication, @article=@article, @schema_replication='true'            
  5028.             IF @@ERROR <> 0 OR @retcode <> 0
  5029.             BEGIN
  5030.                 RAISERROR(21198, 16, -1)
  5031.                 goto FAILURE
  5032.             END
  5033.         END
  5034.  
  5035.         /*
  5036.         **  Set all bits to '1' for all columns in the primary key.
  5037.         */
  5038.         ELSE
  5039.         BEGIN
  5040.             SELECT @indid = indid FROM sysindexes WHERE id = @objid AND (status & 2048) <> 0    /* PK index */
  5041.             /*
  5042.             **  First we'll figure out what the keys are.
  5043.             */
  5044.             SELECT @i = 1
  5045.             WHILE (@i <= 16)
  5046.             BEGIN
  5047.                 SELECT @pkkey = INDEX_COL(@source_object, @indid, @i)
  5048.                 if @pkkey is NULL
  5049.                     break
  5050.                 EXECUTE @retcode  = dbo.sp_mergearticlecolumn @publication, @article, @pkkey, 'add'
  5051.                 IF @@ERROR <> 0 OR @retcode <> 0
  5052.                 BEGIN
  5053.                     RAISERROR(21198, 16, -1)
  5054.                     goto FAILURE
  5055.                 END
  5056.                 select @i = @i + 1
  5057.             END
  5058.             /*
  5059.             ** make sure any existing rowguidcol is in the partition. We can not live without it.
  5060.             */
  5061.             select @colname=NULL
  5062.             select @colname = name from syscolumns where id = @objid 
  5063.                 and ColumnProperty(@objid, name, 'isrowguidcol') = 1
  5064.             if @colname is not NULL
  5065.             BEGIN
  5066.                 EXECUTE @retcode  = dbo.sp_mergearticlecolumn @publication, @article, @colname, 'add'
  5067.                 if @@error<>0 or @retcode<>0
  5068.                     goto FAILURE
  5069.             END
  5070.         END
  5071.  
  5072.         exec @retcode = sp_MSfillupmissingcols @publication, @source_object
  5073.         if @retcode<>0 or @@ERROR<>0
  5074.             goto FAILURE
  5075.  
  5076.         /*
  5077.         ** For articles with subset filter clause - set the pub type to subset
  5078.         */
  5079.         if len(@subset_filterclause) > 0
  5080.             begin
  5081.                 execute @retcode = dbo.sp_MSsubsetpublication @publication
  5082.                 if @@ERROR <> 0 or @retcode<>0
  5083.                     goto FAILURE
  5084.             end                     
  5085.  
  5086.         SELECT @dbname =  DB_NAME()
  5087.         
  5088.         SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + 
  5089.             '.dbo.sp_MSadd_article'
  5090.         EXECUTE @retcode = @distproc
  5091.             @publisher = @@SERVERNAME,
  5092.             @publisher_db = @dbname,
  5093.             @publication = @publication,
  5094.             @article = @article,
  5095.             @destination_object = @destination_object,
  5096.             @source_owner = @source_owner,
  5097.             @source_object = @source_object,
  5098.             @description = @description
  5099.             -- @article_id = NULL
  5100.         IF @@ERROR <> 0 or @retcode <> 0
  5101.             BEGIN
  5102.                 goto FAILURE
  5103.             END
  5104.  
  5105.         if @bump_to_80=1
  5106.             begin
  5107.                 exec @retcode = sp_MSBumpupCompLevel @pubid, 40
  5108.                 if @@ERROR<>0 or @retcode<>0
  5109.                     goto FAILURE
  5110.             end
  5111.         if @needs_pickup=1
  5112.             begin
  5113.                 declare @needs_pick_value int 
  5114.                 select @needs_pick_value=5 --new_inactive status
  5115.                 update sysmergearticles set status=@needs_pick_value where artid = @artid and pubid=@pubid
  5116.                 if @@ERROR<>0
  5117.                     goto FAILURE
  5118.  
  5119.                 /* 
  5120.                 ** Add the guid column to the user table if needed, cause snapshot_ready>0 would imply
  5121.                 ** this article has got a rowguid column. No need to add index, triggers, or procedures
  5122.                 ** as snapshot run will take care of those.
  5123.                 */
  5124.                 execute @retcode = dbo.sp_MSaddguidcolumn @source_owner, @source_object
  5125.                 if @@ERROR <> 0 OR  @retcode <> 0  -- NOTE: new change
  5126.                     goto FAILURE
  5127.  
  5128.                 execute @retcode = dbo.sp_MSaddguidindex @publication, @source_owner, @source_object
  5129.                 if @@ERROR <> 0 OR @retcode <> 0
  5130.                     goto FAILURE
  5131.                     
  5132.             end
  5133.  
  5134.         COMMIT TRAN 
  5135.  
  5136.         /* If the article status is active adding the merge triggers to the base table */
  5137.          
  5138.         return (0)
  5139. FAILURE:
  5140.         RAISERROR (20009, 16, -1, @article, @publication)
  5141.         if @@TRANCOUNT > 0
  5142.         begin
  5143.             ROLLBACK TRANSACTION sp_addmergearticle
  5144.             COMMIT TRANSACTION
  5145.         end
  5146.         return (1)
  5147. go
  5148.  
  5149. exec dbo.sp_MS_marksystemobject sp_addmergearticle
  5150. go
  5151.  
  5152. grant execute on dbo.sp_addmergearticle to public
  5153. go
  5154.  
  5155. raiserror('Creating procedure sp_MSchangemergeschemaarticle', 0,1)
  5156. GO
  5157.  
  5158. CREATE PROCEDURE sp_MSchangemergeschemaarticle (
  5159.     @pubid uniqueidentifier,
  5160.     @artid uniqueidentifier,
  5161.     @property sysname,
  5162.     @value nvarchar(2000)
  5163.     ) AS
  5164.     
  5165.     set nocount on
  5166.  
  5167.     /*
  5168.     ** No need to bump the compatibility level
  5169.     ** here as the compatibility level for
  5170.     ** a publication with a schema-only article 
  5171.     ** is already 80
  5172.     */
  5173.     declare @schema_option   binary(8)
  5174.     declare @precmdid        tinyint
  5175.     declare @creation_script nvarchar(255)
  5176.     declare @statusid        tinyint
  5177.     declare @type            tinyint
  5178.     declare @source_object   sysname
  5179.     declare @valid_schema_options int
  5180.     declare @retcode         int
  5181.  
  5182.     /* 
  5183.     ** Parameter Check: @property
  5184.     ** Check to make sure that @property is a valid property in 
  5185.     ** sysmergeschemaarticles.
  5186.     */
  5187.     select @property = lower(@property collate SQL_Latin1_General_CP1_CS_AS)
  5188.     if @property NOT IN ('description',
  5189.                          'pre_creation_command',
  5190.                          'creation_script',
  5191.                          'status',
  5192.                          'schema_option',
  5193.                          'destination_owner',
  5194.                          'destination_object')
  5195.     begin
  5196.         raiserror(21224, 16, -1, @property)
  5197.         return (1)
  5198.     end  
  5199.  
  5200.     select @type = type, @source_object = object_name(objid)
  5201.       from sysmergeextendedarticlesview
  5202.      where pubid = @pubid
  5203.        and artid = @artid 
  5204.  
  5205.     -- Since all property changes will take the form of 
  5206.     -- simple update stataments, no transaction will be 
  5207.     -- started. 
  5208.  
  5209.     if @property = N'description'
  5210.     begin
  5211.         update sysmergeschemaarticles 
  5212.            set description = @value 
  5213.          where pubid = @pubid
  5214.            and artid = @artid
  5215.             
  5216.         if @@error <> 0
  5217.             return 1
  5218.     end
  5219.     else if @property = N'pre_creation_command'
  5220.     begin
  5221.         /*
  5222.         ** The value for the pre_creation_command
  5223.         ** property must be either 'none' or 'drop'  
  5224.         */
  5225.         select @value = lower(@value collate SQL_Latin1_General_CP1_CS_AS)
  5226.         if @value not in (N'none', N'drop')
  5227.         begin
  5228.             raiserror(21223, 16, -1)
  5229.             return (1)
  5230.         end
  5231.  
  5232.         if @value = N'none'
  5233.             select @precmdid = 0
  5234.         else if @value = N'drop'
  5235.             select @precmdid = 1 
  5236.             
  5237.         update sysmergeschemaarticles
  5238.            set pre_creation_command = @precmdid
  5239.          where pubid = @pubid
  5240.            and artid = @artid
  5241.  
  5242.         if @@error <> 0
  5243.             return (1)
  5244.  
  5245.     end   
  5246.     else if @property = N'creation_script'
  5247.     begin
  5248.         if @value is NULL or @value = N''
  5249.         begin
  5250.             /*
  5251.             ** Existing schema option must not be 
  5252.             ** 0x0000000000000000 if the creation_script 
  5253.             ** path has to be set to null
  5254.             */
  5255.  
  5256.             select @schema_option = schema_option from sysmergeschemaarticles
  5257.             where pubid = @pubid and artid = @artid
  5258. /*            
  5259.             if @schema_option = 0x0000000000000000
  5260.             begin
  5261.                 raiserror(21218, 16, -1)
  5262.                 return (1)
  5263.             end
  5264. */
  5265.  
  5266.         end
  5267.  
  5268.         update sysmergeschemaarticles 
  5269.            set creation_script = @value
  5270.          where pubid = @pubid 
  5271.            and artid = @artid     
  5272.  
  5273.         if @@error <> 0
  5274.             return (1)
  5275.  
  5276.     end 
  5277.     else if @property = N'status'
  5278.     begin
  5279.         select @value = lower(@value collate SQL_Latin1_General_CP1_CS_AS)
  5280.  
  5281.         if @value not in ('active', 'unsynced')
  5282.         begin
  5283.             raiserror(20075, 16, -1)
  5284.             return (1)
  5285.         end
  5286.  
  5287.         if @value = N'unsynced'
  5288.             select @statusid = 1
  5289.         else if @value = N'active'
  5290.             select @statusid = 2
  5291.  
  5292.         update sysmergeschemaarticles
  5293.            set status = @statusid 
  5294.          where pubid = @pubid
  5295.            and artid = @artid
  5296.         
  5297.         if @@error <> 0
  5298.             return (1)
  5299.     end
  5300.     else if @property = N'schema_option'
  5301.     begin
  5302.        
  5303.         if @value is null
  5304.         begin
  5305.             raiserror(14146, 16,1)
  5306.             return (1)
  5307.         end
  5308.  
  5309.         create table #tab_changeschemaarticle (value varbinary(8) NULL)
  5310.         if @@error <> 0
  5311.         begin
  5312.             return(1)
  5313.         end
  5314.     
  5315.         declare @cmd nvarchar(200)
  5316.         select @cmd = 'insert into #tab_changeschemaarticle (value) values (@value)'
  5317.         exec @retcode= dbo.sp_executesql @cmd, N'@value nvarchar(2000)', @value = @value
  5318.  
  5319.         if @@error <> 0 or @retcode <> 0
  5320.         begin
  5321.             drop table #tab_changeschemaarticle    
  5322.             return (1)
  5323.         end
  5324.     
  5325.         select @schema_option = fn_replprepadbinary8(value) 
  5326.           from #tab_changeschemaarticle
  5327.      
  5328.         /*
  5329.         ** schema_option can only contain the bits 0x0000000000000001 and
  5330.         ** 0x0000000000002000
  5331.         ** for schema only articles except view. View articles can contain 
  5332.         ** the options 0x0000000000000010, 0x0000000000000020, and 0x0000000000000100 
  5333.         ** in addition to the aforementioned options.
  5334.         */
  5335.         if @type = 0x40
  5336.         begin
  5337.  
  5338.             -- Since only the lower 32 bits of @schema_option are
  5339.             -- currently, the following check is sufficient.
  5340.             declare @schema_option_lodword int
  5341.             select @valid_schema_options = 0x2151
  5342.             select @schema_option_lodword = fn_replgetbinary8lodword(@schema_option)
  5343.             if (@schema_option_lodword & ~@valid_schema_options) <> 0
  5344.             begin
  5345.                 raiserror (21229, 16, -1)
  5346.                 return (1)
  5347.             end
  5348.         end
  5349.         else if @schema_option not in (0x0000000000000000,
  5350.                                        0x0000000000000001,
  5351.                                        0x0000000000002000,
  5352.                                        0x0000000000002001)
  5353.         begin
  5354.             drop table #tab_changeschemaarticle 
  5355.             raiserror (21222, 16, -1)
  5356.             return (1)
  5357.         end
  5358.  
  5359.         if exists (select * from #tab_changeschemaarticle 
  5360.                     where value = 0x0000000000000000)
  5361.         begin
  5362.  
  5363.             select @creation_script = NULL
  5364.             select @creation_script = creation_script 
  5365.               from sysmergeschemaarticles
  5366.              where pubid = @pubid
  5367.                and artid = @artid
  5368. /*            
  5369.             if @creation_script is NULL or 
  5370.                @creation_script = N''
  5371.             begin
  5372.                 raiserror(21218, 16, -1) 
  5373.                 drop table #tab_changeschemaarticle    
  5374.                 return (1)
  5375.             end
  5376. */
  5377.         end 
  5378.             
  5379.         update sysmergeschemaarticles
  5380.            set schema_option = fn_replprepadbinary8(tab.value)
  5381.           from #tab_changeschemaarticle tab
  5382.          where pubid = @pubid 
  5383.            and artid = @artid
  5384.         
  5385.         if @@error <> 0
  5386.         begin
  5387.             drop table #tab_changeschemaarticle    
  5388.             return (1)
  5389.         end
  5390.  
  5391.         drop table #tab_changeschemaarticle    
  5392.             
  5393.         if @@error <> 0
  5394.             return (1)
  5395.     end
  5396.     else if @property = N'destination_owner'
  5397.     begin
  5398.         select @value = rtrim(@value) 
  5399.         update sysmergeschemaarticles 
  5400.            set destination_owner = @value
  5401.          where pubid = @pubid
  5402.            and artid = @artid
  5403.         
  5404.         if @@error <> 0
  5405.             return (1)
  5406.     end
  5407.     else if @property = N'destination_object'
  5408.     begin
  5409.         select @value = rtrim(@value) 
  5410.         if @value is null or @value = ''
  5411.         begin
  5412.             select @value = @source_object
  5413.         end
  5414.         update sysmergeschemaarticles
  5415.            set destination_object = @value
  5416.          where pubid = @pubid
  5417.            and artid = @artid        
  5418.     end
  5419.  
  5420.     return (0)        
  5421.  
  5422. go
  5423.  
  5424. exec dbo.sp_MS_marksystemobject sp_MSchangemergeschemaarticle
  5425. go
  5426.  
  5427. raiserror('Creating procedure sp_changemergearticle', 0,1)
  5428. GO
  5429.  
  5430. CREATE PROCEDURE sp_changemergearticle (
  5431.     @publication sysname,              /* Publication name */
  5432.     @article sysname,              /* Article name */
  5433.     @property sysname = NULL,          /* The property to change */
  5434.     @value nvarchar(2000) = NULL,             /* The new property value */
  5435.     @force_invalidate_snapshot bit = 0,    /* Force invalidate existing snapshot */
  5436.     @force_reinit_subscription bit = 0    /* Force reinit subscription */
  5437.     ) AS
  5438.  
  5439.     SET NOCOUNT ON
  5440.  
  5441.     /*
  5442.     ** Declarations.
  5443.     */
  5444.     declare @sp_resolver            sysname
  5445.     declare @db_name            sysname
  5446.     declare @intvalue            bigint
  5447.     declare @artid              uniqueidentifier
  5448.     declare @pubid              uniqueidentifier
  5449.     declare @artidstr           nvarchar(38)
  5450.     declare @object_view        sysname
  5451.     declare @vertical            int
  5452.     declare @pubidstr           nvarchar(38)
  5453.     declare @object             sysname
  5454.     declare @owner              sysname
  5455.     declare @identity_support     int
  5456.     declare @column_list        nvarchar(4000)
  5457.     declare @resolver_clsid     nvarchar(50)
  5458.     declare @article_resolver   nvarchar(255)
  5459.     declare @resolver_clsid_str nvarchar(55)
  5460.     declare @article_resolver_str   nvarchar(270)
  5461.     declare @value_str            nvarchar(270)
  5462.     declare @retcode            int
  5463.     declare @statusid           int
  5464.     declare @precmdid           tinyint
  5465.     declare @regkey             nvarchar(255)
  5466.     declare @distributor        sysname
  5467.     declare @distribdb        sysname
  5468.     declare @distproc           nvarchar(300)
  5469.     declare @snapshot_ready        int
  5470.     declare @schemaversion      int 
  5471.     declare @objid                int
  5472.     declare @schemaguid         uniqueidentifier
  5473.     declare @schematype         int
  5474.     declare @schematext         nvarchar(2000)
  5475.     declare @type               tinyint
  5476.     declare @allow_interactive_bit    int
  5477.     declare @additive_resolver        sysname
  5478.     declare @average_resolver        sysname
  5479.     declare @mindate_resolver        sysname
  5480.     declare @maxdate_resolver        sysname
  5481.     declare @minimum_resolver        sysname
  5482.     declare @maximum_resolver        sysname
  5483.     declare @mergetxt_resolver        sysname
  5484.     declare @pricolumn_resolver        sysname
  5485.     declare @pre_command            int
  5486.     declare @coltrack                int
  5487.  
  5488.     declare @qual_object_view        nvarchar(140)
  5489.     declare @qual_object            nvarchar(140)
  5490.     declare @quoted_object            nvarchar(140)
  5491.     declare @bump_to_80             bit
  5492.     declare @schema_option          binary(8)
  5493.     declare @old_schema_option      binary(8)
  5494.     declare @published_in_tran_pub_bit bit
  5495.  
  5496.     /*
  5497.     ** Security Check
  5498.     */
  5499.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  5500.     IF @@ERROR <> 0 or @retcode <> 0
  5501.         return (1)
  5502.  
  5503.     select @db_name = db_name()
  5504.     select @bump_to_80 = 0
  5505.  
  5506.     /*
  5507.     ** Check to see if the database has been activated for publication.
  5508.     */
  5509.  
  5510.     if (select category & 4
  5511.           FROM master..sysdatabases
  5512.          WHERE name = @db_name collate database_default) = 0
  5513.  
  5514.     BEGIN
  5515.         RAISERROR (14013, 16, -1)
  5516.         RETURN (1)
  5517.     END
  5518.  
  5519.     /*
  5520.     ** Parameter Check:  @publication.
  5521.     ** Make sure that the publication exists.
  5522.     */
  5523.  
  5524.     if @publication IS NULL
  5525.         BEGIN
  5526.             RAISERROR (14043, 16, -1, '@publication')
  5527.             RETURN (1)
  5528.         END
  5529.  
  5530.     select @pubid = pubid, @snapshot_ready=snapshot_ready from sysmergepublications 
  5531.         where name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=@db_name
  5532.     if @pubid IS NULL
  5533.         BEGIN
  5534.             RAISERROR (20026, 16, -1, @publication)
  5535.             RETURN (1)
  5536.         END
  5537.     
  5538.     select @db_name = db_name from sysmergesubscriptions
  5539.         where (pubid=@pubid) and (subid=@pubid)
  5540.         IF @db_name <> @db_name
  5541.         BEGIN
  5542.             RAISERROR (20047, 16, -1)
  5543.             RETURN (1)
  5544.         END
  5545.  
  5546.     /*
  5547.     ** Parameter Check:  @property.
  5548.     ** If the @property parameter is NULL, print the options.
  5549.     */
  5550.  
  5551.     if @property IS NULL
  5552.         BEGIN
  5553.             CREATE TABLE #tab1 (properties sysname collate database_default)
  5554.             INSERT INTO #tab1 VALUES ('description')
  5555.             INSERT INTO #tab1 VALUES ('pre_creation_command')
  5556.             INSERT INTO #tab1 VALUES ('creation_script')
  5557.             INSERT INTO #tab1 VALUES ('column_tracking (table article only)')
  5558.             INSERT INTO #tab1 VALUES ('article_resolver (table article only)')
  5559.             INSERT INTO #tab1 VALUES ('resolver_info (table article only)')
  5560.             INSERT INTO #tab1 VALUES ('status')
  5561.             INSERT INTO #tab1 VALUES ('subset_filterclause (table article only)')
  5562.             INSERT INTO #tab1 VALUES ('schema_option')
  5563.             INSERT INTO #tab1 VALUES ('destination_owner')
  5564.                INSERT INTO #tab1 VALUES ('pub_identity_range (table article only)')
  5565.             INSERT INTO #tab1 VALUES ('identity_range (table article only)')
  5566.             INSERT INTO #tab1 VALUES ('threshold (table article only)')
  5567.             INSERT INTO #tab1 VALUES ('verify_resolver_signature')
  5568.             INSERT INTO #tab1 VALUES ('allow_interactive_resolver')
  5569.             INSERT INTO #tab1 VALUES ('check_permissions')
  5570.             INSERT INTO #tab1 VALUES ('published_in_tran_pub')
  5571.             
  5572.             select * FROM #tab1
  5573.             RETURN (0)
  5574.         END
  5575.  
  5576.     /*
  5577.     ** Check to see that the article exists in sysmergearticles.
  5578.     ** Fetch the article identification number.
  5579.     */
  5580.  
  5581.     if @article IS NULL
  5582.         BEGIN
  5583.             RAISERROR (14043, 16, -1, '@article')
  5584.             RETURN (1)
  5585.         END
  5586.  
  5587.     select @artid = artid, 
  5588.            @type = type,
  5589.            @old_schema_option = schema_option,
  5590.            @objid = objid
  5591.      FROM sysmergeextendedarticlesview
  5592.         WHERE name = @article AND pubid = @pubid
  5593.     if @artid IS NULL
  5594.         BEGIN
  5595.             RAISERROR (20027, 16, -1, @article)
  5596.             RETURN (1)
  5597.         END
  5598.  
  5599.     select @pre_command=pre_creation_command, @identity_support = identity_support from sysmergearticles where pubid=@pubid and artid=@artid
  5600.     /*
  5601.     ** Handle the changing of schema only articles property
  5602.     ** in a different procedure
  5603.     */
  5604.     if @type in (0x20, 0x40, 0x80)
  5605.         begin
  5606.             exec @retcode = sp_MSchangemergeschemaarticle @pubid = @pubid,
  5607.                                                            @artid = @artid,
  5608.                                                            @property = @property,
  5609.                                                            @value = @value
  5610.             return @retcode
  5611.         end             
  5612.  
  5613.     /*
  5614.     ** Parameter Check:  @property.
  5615.     ** Check to make sure that @property is a valid property in
  5616.     ** sysmergearticles.
  5617.     */
  5618.     if @property IS NULL OR LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT in 
  5619.                                                     ('name',
  5620.                                                      'description',
  5621.                                                      'pre_creation_command',
  5622.                                                      'creation_script',
  5623.                                                      'column_tracking',
  5624.                                                      'article_resolver',    
  5625.                                                      'resolver_info',
  5626.                                                      'status',
  5627.                                                      'subset_filterclause',
  5628.                                                      'schema_option',
  5629.                                                      'pub_identity_range',
  5630.                                                      'identity_range',
  5631.                                                      'threshold',
  5632.                                                      'verify_resolver_signature',
  5633.                                                      'check_permissions',
  5634.                                                      'allow_interactive_resolver',
  5635.                                                      'destination_owner',
  5636.                                                      'published_in_tran_pub')
  5637.         BEGIN
  5638.             RAISERROR (21259, 16, -1, @property)
  5639.             RETURN (1)
  5640.         END
  5641.         
  5642.     -- COMMENT: the following article properties can not be changed at republisher side
  5643.     if    LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ('article_resolver','resolver_info','column_tracking',
  5644.                     'allow_interactive_resolver','verify_resolver_signature') and 
  5645.             exists (select * from sysmergearticles where objid=@objid and pubid not in 
  5646.                 (select pubid from sysmergepublications where UPPER(publisher)=UPPER(@@servername) 
  5647.                     and publisher_db=@db_name))
  5648.         
  5649.         BEGIN
  5650.             RAISERROR(21400, 16, -1, @article)
  5651.             return (1)
  5652.         END
  5653.  
  5654.     if @identity_support=0 and LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ('pub_identity_range','identity_range','threshold')
  5655.         begin
  5656.             RAISERROR(21257, 16, -1, @property, @article)
  5657.             return (1)
  5658.         end
  5659.  
  5660.     exec @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
  5661.                        @distribdb   = @distribdb OUTPUT
  5662.     IF @@ERROR <> 0 or @retcode <> 0 or @distributor is NULL
  5663.     BEGIN
  5664.         RAISERROR (20036, 16, -1)
  5665.         RETURN (1)
  5666.     END
  5667.  
  5668.     SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSadjust_pub_identity'
  5669.     select @objid=objid, @object = object_name(objid), @vertical=vertical_partition from sysmergearticles where artid=@artid and pubid=@pubid
  5670.     set @artidstr = '''' + convert(nchar(36), @artid) + '''' 
  5671.     set @pubidstr = '''' + convert(nchar(36), @pubid) + '''' 
  5672.     select @sp_resolver         = 'Microsoft SQLServer Stored Procedure Resolver'
  5673.     select @additive_resolver     = 'Microsoft SQL Server Additive Conflict Resolver'
  5674.     select @average_resolver     = 'Microsoft SQL Server Averaging Conflict Resolver'
  5675.     select @minimum_resolver     = 'Microsoft SQL Server Minimum Conflict Resolver'
  5676.     select @maximum_resolver     = 'Microsoft SQL Server Maximum Conflict Resolver'
  5677.     select @mindate_resolver     = 'Microsoft SQL Server DATETIME (Earlier Wins) Conflict Resolver'
  5678.     select @maxdate_resolver     = 'Microsoft SQL Server DATETIME (Later Wins) Conflict Resolver'
  5679.     select @mergetxt_resolver     = 'Microsoft SQL Server Merge Text Columns Conflict Resolver'
  5680.     select @pricolumn_resolver     = 'Microsoft SQL Server Priority Column Resolver'
  5681.  
  5682.     BEGIN TRAN
  5683.     save TRAN changemergearticle
  5684.     /*
  5685.     ** Changing of the following properties would require a snapshot rerun.and reinit, if snapshot is ready
  5686.     */
  5687.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in 
  5688.                                                     ('pre_creation_command',
  5689.                                                      'creation_script',
  5690.                                                      'column_tracking',
  5691.                                                      'subset_filterclause',
  5692.                                                      'schema_option',
  5693.                                                      'destination_owner',
  5694.                                                      'check_permissions',
  5695.                                                      'published_in_tran_pub')
  5696.         and    @snapshot_ready > 0
  5697.     begin
  5698.         if @pre_command<>1 -- 1 means'drop': which is the only option that support reintialization
  5699.         begin
  5700.             raiserror(21416, 16, -1, @property, @article)
  5701.             goto UNDO            
  5702.         end
  5703.         if @force_invalidate_snapshot = 0
  5704.         begin
  5705.             raiserror(20607, 16, -1)
  5706.             goto UNDO
  5707.         end
  5708.         if @force_reinit_subscription = 0
  5709.         begin
  5710.             raiserror(20608, 16, -1)
  5711.             goto UNDO
  5712.         end
  5713.         
  5714.         update sysmergepublications set snapshot_ready=2 where pubid=@pubid and snapshot_ready=1
  5715.         if @@ERROR<>0    
  5716.             GOTO UNDO
  5717.         exec @retcode=sp_MSreinitmergepublication @publication
  5718.         if @@ERROR<>0 or @retcode<>0
  5719.             GOTO UNDO 
  5720.     end
  5721.  
  5722.     /*
  5723.     ** Change the property.
  5724.     */
  5725.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'column_tracking'
  5726.         BEGIN
  5727.             /*
  5728.             ** Check to make sure that we have a valid type.
  5729.             */
  5730.             if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  5731.                 BEGIN
  5732.                     RAISERROR (14137, 16, -1)
  5733.                     goto UNDO
  5734.                 END
  5735.  
  5736.             /*
  5737.             ** Update the syssubsetdefintions table with the new column tracking.
  5738.             */
  5739.             if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  5740.                     update sysmergearticles set column_tracking = 1 where artid=@artid      
  5741.             else
  5742.                     update sysmergearticles set column_tracking = 0 where artid=@artid
  5743.             if @@ERROR <> 0 
  5744.                 goto UNDO
  5745.  
  5746.         END
  5747.  
  5748.     
  5749.     /* pub_identity_range is not stored at distribution database because it is not interested in this value.*/   
  5750.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'pub_identity_range'
  5751.         BEGIN
  5752.             select @intvalue = convert(bigint, @value)
  5753.             if @intvalue<0
  5754.             begin
  5755.                 raiserror(21232, 16, -1)
  5756.                 goto UNDO
  5757.             end
  5758.             update MSrepl_identity_range set pub_range=@intvalue where objid=@objid
  5759.             if @@ERROR<>0
  5760.                 goto UNDO        
  5761.         END
  5762.      
  5763.     /* the property of check permissions is a bitmask of which operation do we want to check for*/   
  5764.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'check_permissions'
  5765.         BEGIN
  5766.             select @intvalue = convert(int, @value)
  5767.             if @intvalue<0
  5768.             begin
  5769.                 raiserror(21232, 16, -1)
  5770.                 goto UNDO
  5771.             end
  5772.             update sysmergearticles set check_permissions=@intvalue
  5773.             if @@ERROR<>0
  5774.                 goto UNDO        
  5775.         END
  5776.  
  5777.  
  5778.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'identity_range'
  5779.         BEGIN
  5780.             select @intvalue = convert(bigint, @value)
  5781.             if @intvalue<0
  5782.             begin
  5783.                 raiserror(21232, 16, -1)
  5784.                 goto UNDO
  5785.             end
  5786.  
  5787.             update MSrepl_identity_range set range=@intvalue where objid=@objid
  5788.             if @@ERROR<>0
  5789.                 goto UNDO
  5790.             exec  @retcode=@distproc @publisher=@@SERVERNAME,
  5791.                                         @publisher_db=@db_name,
  5792.                                         @tablename=@object,
  5793.                                         @range=@intvalue
  5794.                 if @retcode<>0 or @@ERROR<>0
  5795.                     goto UNDO
  5796.  
  5797.         END
  5798.  
  5799.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'threshold'
  5800.         BEGIN
  5801.             select @intvalue = convert(int, @value)
  5802.             if @intvalue<0 or @intvalue>100
  5803.             begin
  5804.                 raiserror(21241, 16, -1)
  5805.                 goto UNDO
  5806.             end
  5807.             update MSrepl_identity_range set threshold=@intvalue where objid=@objid
  5808.             if @@ERROR<>0
  5809.                 goto UNDO
  5810.             exec  @retcode=@distproc @publisher=@@SERVERNAME,
  5811.                                         @publisher_db=@db_name,
  5812.                                         @tablename=@object,
  5813.                                         @threshold=@intvalue
  5814.                 if @retcode<>0 or @@ERROR<>0
  5815.                     goto UNDO
  5816.  
  5817.         END
  5818.  
  5819.      if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='description'
  5820.         BEGIN
  5821.         UPDATE sysmergearticles  SET description = @value WHERE artid = @artid and pubid = @pubid
  5822.             AND pubid = @pubid
  5823.         if @@ERROR <> 0 
  5824.                 goto UNDO
  5825.     END
  5826.  
  5827.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) ='creation_script'
  5828.         BEGIN
  5829.             update sysmergearticles set creation_script=@value where artid=@artid and pubid=@pubid
  5830.             if @@ERROR <> 0 
  5831.                 goto UNDO
  5832.         END
  5833.  
  5834.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'subset_filterclause'
  5835.         BEGIN
  5836.             if @value is not null and @value<>''
  5837.             begin
  5838.             /* check the validity of subset_filterclause */
  5839.             select @object_view=@object
  5840.             select @quoted_object=QUOTENAME(@object)    
  5841.             
  5842.             exec @retcode = sp_MSget_qualified_name @objid, @qual_object OUTPUT
  5843.             if @@ERROR<>0 or @retcode<>0
  5844.                 goto UNDO
  5845.             select @qual_object_view=@qual_object
  5846.             
  5847.             if @vertical=1
  5848.             begin
  5849.               select @object_view='TEMP_VIEW_' + @object
  5850.               select @qual_object_view = QUOTENAME(@object_view)
  5851.               exec @retcode = sp_MSgetcolumnlist @pubid, @column_list OUTPUT, @objid
  5852.               exec ('create view ' + @qual_object_view + ' as select ' + @column_list + ' from ' + @quoted_object)
  5853.               if @@ERROR<>0
  5854.               begin
  5855.                   raiserror(21256, 16, -1, @value, @object)
  5856.                 goto UNDO
  5857.               end
  5858.             end
  5859.             
  5860.             exec ('declare @test int select @test=1 from ' + @qual_object_view + ' ' + @quoted_object + ' where ' + @value)
  5861.             if @@ERROR<>0
  5862.                 begin
  5863.                     if @vertical=1
  5864.                         exec('drop view ' + @qual_object_view)
  5865.                     raiserror(21256, 16, -1, @value, @object)
  5866.                     goto UNDO
  5867.                 end
  5868.             end
  5869.             if @vertical=1
  5870.                 exec('drop view ' + @qual_object_view)
  5871.  
  5872.             update sysmergearticles set subset_filterclause = @value where artid=@artid and pubid=@pubid
  5873.             if @@ERROR<>0 goto UNDO
  5874.             
  5875.             /*
  5876.             ** set the pub type to subset or full as appropriate
  5877.             */
  5878.             execute @retcode = dbo.sp_MSsubsetpublication @publication
  5879.             if @@ERROR <> 0 OR @retcode <> 0
  5880.                 goto UNDO
  5881.                 
  5882.         END
  5883.  
  5884.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) ='article_resolver'
  5885.         BEGIN
  5886.  
  5887.             if @value IS NULL OR @value = 'default' OR @value = ''
  5888.                 begin
  5889.                     set @article_resolver = NULL
  5890.                     set @resolver_clsid = NULL
  5891.                 end                 
  5892.                     
  5893.             else
  5894.                 begin
  5895.                     EXECUTE @retcode = master.dbo.xp_regread 'HKEY_LOCAL_MACHINE',
  5896.                                       'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\ArticleResolver',
  5897.                                       @value,
  5898.                                       @param = @resolver_clsid OUTPUT
  5899.                     IF @@ERROR <> 0 or @retcode <> 0 or @resolver_clsid IS NULL
  5900.                         BEGIN
  5901.                             RAISERROR (20020, 16, -1)
  5902.                             goto UNDO
  5903.                         END
  5904.                 end                     
  5905.                     
  5906.             /*
  5907.             ** Update the appropriate column in sysmergearticles with the new article resolver name.
  5908.             ** Note this could affect multiple publication if the same table spans publications
  5909.             */
  5910.  
  5911.             /* NOTE: new change */
  5912.                 exec @retcode = dbo.sp_MSchangearticleresolver @value, @resolver_clsid, @artid
  5913.                 if @@ERROR <> 0 OR @retcode <> 0
  5914.                     begin
  5915.                         goto UNDO                          
  5916.                     end  
  5917.                 
  5918.                 declare one_pub CURSOR LOCAL FAST_FORWARD FOR 
  5919.                     select DISTINCT pubid from sysmergearticles where artid=@artid
  5920.                 FOR READ ONLY
  5921.                 open one_pub
  5922.                 fetch next from one_pub into @pubid
  5923.                  
  5924.                 while (@@fetch_status <> -1)
  5925.                     begin
  5926.                         select @snapshot_ready=snapshot_ready from sysmergepublications 
  5927.                             where pubid = @pubid
  5928.                         /* Insert the sp_MSchangearticleresolver schema change only if the publication's snapshot is ready */
  5929.                         if (@snapshot_ready > 0)
  5930.                             begin
  5931.                                 select @schemaversion = schemaversion from sysmergeschemachange
  5932.                                 if (@schemaversion is NULL) 
  5933.                                     set @schemaversion = 1
  5934.                                 else  
  5935.                                     select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
  5936.                                 set @schemaguid = newid()
  5937.                                 set @schematype = 8
  5938.                                 if @value is not NULL and @value <> ''
  5939.                                     select @schematext = 'exec dbo.sp_MSchangearticleresolver ' + quotename(@value) + ',' + '''' + @resolver_clsid + '''' + ',' + '''' + convert(nchar(36), @artid) + ''''
  5940.                                 else
  5941.                                     select @schematext = 'exec dbo.sp_MSchangearticleresolver NULL, NULL,' + '''' + convert(nchar(36), @artid) + ''''
  5942.                                      
  5943.                                 exec @retcode = dbo.sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext 
  5944.                                 if @@ERROR <> 0 OR @retcode <> 0
  5945.                                     goto UNDO
  5946.                             end                                        
  5947.                         fetch next from one_pub into @pubid
  5948.                     end 
  5949.                 close one_pub
  5950.                 deallocate one_pub
  5951.  
  5952.         END /* for property = 'article_resolver' */
  5953.  
  5954.  
  5955.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) ='resolver_info'
  5956.         BEGIN
  5957.             /* allow non-sp's as resolver info; don't change the resolver class */
  5958.             select     @article_resolver = article_resolver, 
  5959.                     @resolver_clsid = resolver_clsid from
  5960.                     sysmergearticles where artid = @artid
  5961.  
  5962.             -- Convert NULL value to 'NULL' string to be used for constructing schema text
  5963.             -- we do not want to change NULL value to ''.
  5964.             select @article_resolver_str=QUOTENAME(@article_resolver)
  5965.             select @resolver_clsid_str = @resolver_clsid
  5966.             select @value_str=@value
  5967.             if @article_resolver is null set @article_resolver_str = 'NULL'
  5968.             if @resolver_clsid is null set @resolver_clsid_str = 'NULL'
  5969.             if @value is null set @value_str = 'NULL'
  5970.  
  5971.             /* The following resolvers expect the @resolver_info to be NON NULL */
  5972.             if  @article_resolver = @sp_resolver or 
  5973.                 @article_resolver = @additive_resolver or
  5974.                 @article_resolver = @average_resolver or
  5975.                 @article_resolver = @minimum_resolver or
  5976.                 @article_resolver = @maximum_resolver or
  5977.                 @article_resolver = @mindate_resolver or
  5978.                 @article_resolver = @maxdate_resolver or
  5979.                 @article_resolver = @mergetxt_resolver or
  5980.                 @article_resolver = @pricolumn_resolver
  5981.                 begin
  5982.                     if @value IS NULL or @value = ''
  5983.                         begin
  5984.                             RAISERROR (21301, 16, -1, @article_resolver)
  5985.                             goto UNDO
  5986.                         end
  5987.                 end
  5988.  
  5989.             /* The SP resolver expect the @resolver_info to be the name of sp */
  5990.             if  @article_resolver = @sp_resolver
  5991.                 begin
  5992.                     if not exists (select * from sysobjects where id = object_id(@value) and ( type = 'P' or type = 'X'))
  5993.                         begin
  5994.                             raiserror(21343, 16, -1, @value)
  5995.                             goto UNDO
  5996.                         end
  5997.                 end
  5998.             /*
  5999.             ** If article resolver is 'mindate/maxdate resolver', make sure that resolver_info refers to a column that is of datatype 'datetime' or smalldatetime
  6000.             */
  6001.             if  @article_resolver = @mindate_resolver or
  6002.                 @article_resolver = @maxdate_resolver
  6003.                 begin
  6004.                     if not exists (select * from syscolumns where id = @objid and name=@value and type_name(xtype)='datetime' or type_name(xtype) = 'smalldatetime' )
  6005.                         begin
  6006.                             RAISERROR (21302, 16, -1, @article_resolver)
  6007.                             goto UNDO
  6008.                         end
  6009.                 end
  6010.  
  6011.             /* The following resolvers expect the article to be column trcaked - warn that the default resolver migh be used */
  6012.             if  @article_resolver = @additive_resolver or
  6013.                 @article_resolver = @average_resolver
  6014.                 begin
  6015.                     select @coltrack = column_tracking from sysmergearticles where artid = @artid
  6016.                     if @coltrack = 0
  6017.                         begin
  6018.                             RAISERROR (21303, 10, -1, @article, @article_resolver)
  6019.                         end
  6020.                         
  6021.                 end
  6022.                 
  6023.  
  6024.             /*
  6025.             ** Update the appropriate column in sysmergearticles with the new resolver info.
  6026.             ** Note this could affect multiple publication if the same table spans publications
  6027.             */
  6028.                 exec @retcode = dbo.sp_MSchangearticleresolver @article_resolver, @resolver_clsid, @artid, @value
  6029.                 if @@ERROR <> 0 OR @retcode <> 0
  6030.                     begin
  6031.                         goto UNDO                          
  6032.                     end         
  6033.                 declare one_pub CURSOR LOCAL FAST_FORWARD FOR 
  6034.                     select DISTINCT pubid from sysmergearticles where artid=@artid
  6035.                 FOR READ ONLY
  6036.                 open one_pub
  6037.                 fetch next from one_pub into @pubid
  6038.                  
  6039.                 while (@@fetch_status <> -1)
  6040.                     begin
  6041.                         select @snapshot_ready=snapshot_ready from sysmergepublications 
  6042.                             where pubid = @pubid
  6043.                         /* Insert the sp_MSchangearticleresolver schema change only if the publication's snapshot is ready */
  6044.                         if (@snapshot_ready > 0)
  6045.                             begin
  6046.                                 select @schemaversion = schemaversion from sysmergeschemachange
  6047.                                 if (@schemaversion is NULL) set @schemaversion = 1
  6048.                                 else  
  6049.                                     select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
  6050.                                 set @schemaguid = newid()
  6051.                                 set @schematype = 8
  6052.                                 select @schematext = '
  6053.                                     declare @cmd nvarchar(1000) 
  6054.                                     set @cmd=''exec dbo.sp_MSchangearticleresolver @article_resolver=@ar, @resolver_clsid=@rc, @artid=@ai, @resolver_info=@ri''
  6055.                                     exec dbo.sp_executesql @cmd, N''@ar nvarchar(255),@rc nvarchar(40),@ai uniqueidentifier,@ri sysname'',
  6056.                                         @ar=' + @article_resolver_str + ', 
  6057.                                         @rc=''' + @resolver_clsid_str + ''',
  6058.                                         @ai=''' + convert(nchar(36), @artid) + ''',
  6059.                                         @ri=''' + @value_str + ''''
  6060.                                  
  6061.                                 exec @retcode = dbo.sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext 
  6062.                                 if @@ERROR <> 0 OR @retcode <> 0
  6063.                                     begin
  6064.                                         goto UNDO                          
  6065.                                     end
  6066.                             end                             
  6067.                         fetch next from one_pub into @pubid
  6068.                     end 
  6069.                 close one_pub
  6070.                 deallocate one_pub
  6071.  
  6072.         END /* for property = 'resolver_info' */
  6073.  
  6074.  
  6075.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'pre_creation_command'
  6076.         BEGIN
  6077.  
  6078.             /*
  6079.             ** Check to make sure that we have a valid pre_creation_cmd.
  6080.             */
  6081.  
  6082.             if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('none', 'drop', 'delete', 'truncate')
  6083.                 BEGIN
  6084.                     RAISERROR (14061, 16, -1)
  6085.                     goto UNDO
  6086.                 END
  6087.  
  6088.             /*
  6089.             ** Determine the integer value for the pre_creation_cmd.
  6090.             */
  6091.  
  6092.             if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'none'
  6093.                 select @precmdid = 0
  6094.             else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
  6095.                 select @precmdid = 1
  6096.             else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'delete'
  6097.                 select @precmdid = 2
  6098.             else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'truncate'
  6099.                 select @precmdid = 3
  6100.  
  6101.             /*
  6102.             ** Update the article with the new pre_creation_cmd.
  6103.             */
  6104.             UPDATE sysmergearticles
  6105.                 SET pre_creation_command = @precmdid
  6106.                 WHERE artid = @artid
  6107.                 AND pubid = @pubid
  6108.  
  6109.             if @@ERROR <> 0 
  6110.                 goto UNDO
  6111.  
  6112.         END
  6113.  
  6114.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'status'
  6115.         BEGIN
  6116.  
  6117.             /*
  6118.             ** Check to make sure that we have a valid status
  6119.             */
  6120.  
  6121.             if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('active', 'unsynced', 'new_inactive', 'new_active')
  6122.                 BEGIN
  6123.                     RAISERROR (20075, 16, -1)
  6124.                     goto UNDO
  6125.                 END
  6126.  
  6127.             /*
  6128.             ** Determine the integer value for the type.
  6129.             */
  6130.  
  6131.             if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'unsynced'
  6132.                 select @statusid = 1
  6133.             else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'active'
  6134.                 select @statusid = 2
  6135.             else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'new_inactive'
  6136.                 select @statusid = 5
  6137.             else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'new_active'
  6138.                 select @statusid = 6
  6139.  
  6140.             /*
  6141.             ** Update the article with the new type. The same base table might be 
  6142.             ** in multiple publications - so qualify  with pubid.
  6143.             */
  6144.             UPDATE sysmergearticles
  6145.                 SET status = @statusid
  6146.                 WHERE artid = @artid and pubid = @pubid
  6147.  
  6148.             if @@ERROR <> 0 
  6149.                 goto UNDO
  6150.  
  6151.         END
  6152.  
  6153.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'destination_owner'
  6154.         BEGIN
  6155.             IF @value IS NULL or @value=''
  6156.                 select @value = 'dbo'                      
  6157.             UPDATE sysmergearticles SET destination_owner = @value
  6158.                 WHERE artid = @artid
  6159.                 AND pubid = @pubid
  6160.             if @@ERROR <> 0
  6161.                 BEGIN
  6162.                     goto UNDO
  6163.                 END
  6164.         END
  6165.     
  6166.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'schema_option'
  6167.         BEGIN
  6168.         
  6169.             IF @value IS NULL
  6170.                 BEGIN
  6171.                     RAISERROR(14146, 16,1)
  6172.                     goto UNDO
  6173.                 END
  6174.  
  6175.             CREATE TABLE #tab_changearticle (value varbinary(8) NULL)
  6176.                                  
  6177.             IF @@ERROR <> 0 
  6178.                 BEGIN
  6179.                     goto UNDO
  6180.                 END
  6181.             
  6182.             declare @cmd nvarchar(200)
  6183.             select @cmd = 'insert into #tab_changearticle (value) values (@value)'
  6184.             exec @retcode= dbo.sp_executesql @cmd, N'@value nvarchar(2000)', @value = @value
  6185.  
  6186.             IF @@ERROR <> 0 or @retcode <> 0
  6187.                 BEGIN
  6188.                     goto UNDO
  6189.                 END
  6190.                       
  6191.             SELECT @schema_option = fn_replprepadbinary8(value) 
  6192.               FROM #tab_changearticle
  6193.  
  6194.             DECLARE @schema_option_lodword INT
  6195.             DECLARE @old_schema_option_lodword INT
  6196.             DECLARE @xprop_schema_option INT
  6197.             DECLARE @collation_schema_option INT
  6198.             SELECT @xprop_schema_option = 0x00002000
  6199.             SELECT @collation_schema_option = 0x00001000
  6200.             SELECT @schema_option_lodword = fn_replgetbinary8lodword(@schema_option)
  6201.             SELECT @old_schema_option_lodword = CONVERT(INT, SUBSTRING(@old_schema_option, 5, 4))
  6202.             
  6203.             -- Raise warnings only when we are enabling the Shiloh specific
  6204.             -- options
  6205.             IF ((@old_schema_option_lodword & @collation_schema_option) = 0)
  6206.                 AND 
  6207.                ((@schema_option_lodword & @collation_schema_option) <> 0)
  6208.             BEGIN
  6209.                 RAISERROR(21389, 10, -1, @publication)
  6210.                 SELECT @bump_to_80 = 1
  6211.             END
  6212.             
  6213.             IF((@old_schema_option_lodword & @xprop_schema_option) = 0)
  6214.               AND 
  6215.               ((@schema_option_lodword & @xprop_schema_option) <> 0)
  6216.             BEGIN
  6217.                 RAISERROR(21390, 10, -1, @publication)
  6218.                 SELECT @bump_to_80 = 1
  6219.             END
  6220.  
  6221.             UPDATE sysmergearticles 
  6222.                SET schema_option = fn_replprepadbinary8(tab.value) from 
  6223.                 #tab_changearticle tab 
  6224.                 WHERE artid = @artid
  6225.                 AND pubid = @pubid
  6226.             if @@ERROR <> 0
  6227.                 BEGIN
  6228.                 DROP TABLE #tab_changearticle 
  6229.                 goto UNDO
  6230.                 END
  6231.                 
  6232.             DROP TABLE #tab_changearticle 
  6233.                                  
  6234.             IF @@ERROR <> 0 
  6235.                 BEGIN
  6236.                     goto UNDO
  6237.                 END
  6238.  
  6239.         END
  6240.  
  6241.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'verify_resolver_signature'
  6242.         BEGIN
  6243.             if @value NOT IN ('1', '0')
  6244.                 BEGIN
  6245.                     raiserror(21344, 16, -1, '"verify_resolver_signature"')
  6246.                     goto UNDO
  6247.                 END
  6248.  
  6249.             update sysmergearticles set verify_resolver_signature = convert(int, @value) 
  6250.             where artid = @artid and pubid = @pubid
  6251.             if @@ERROR<>0
  6252.                 goto UNDO
  6253.         END
  6254.  
  6255.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_interactive_resolver'
  6256.         BEGIN
  6257.  
  6258.             /* Check to make sure that we have a true/false. */
  6259.  
  6260.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  6261.                 BEGIN
  6262.                     RAISERROR (14148, 16, -1, 'allow_interactive_resolver')
  6263.                     goto UNDO
  6264.                 END
  6265.  
  6266.             /* Determine the bit value. */
  6267.  
  6268.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  6269.                 SET @allow_interactive_bit = 1
  6270.             ELSE
  6271.                 SET @allow_interactive_bit = 0
  6272.     
  6273.             /* Update the subscription with the new 'allow_interactive_resolver' value. */
  6274.             update sysmergearticles set allow_interactive_resolver = @allow_interactive_bit
  6275.                 where artid = @artid and pubid = @pubid
  6276.             IF @@ERROR <> 0
  6277.                 BEGIN
  6278.                     RAISERROR (14053, 16, -1)
  6279.                     goto UNDO
  6280.                 END
  6281.  
  6282.         END
  6283.  
  6284.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'published_in_tran_pub'
  6285.         BEGIN
  6286.  
  6287.             /* Check to make sure that we have a true/false. */
  6288.  
  6289.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  6290.                 BEGIN
  6291.                     RAISERROR (14148, 16, -1, 'published_in_tran_pub')
  6292.                     goto UNDO
  6293.                 END
  6294.  
  6295.             /* Determine the bit value. */
  6296.  
  6297.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  6298.                 SET @published_in_tran_pub_bit = 1
  6299.             ELSE
  6300.                 SET @published_in_tran_pub_bit = 0
  6301.     
  6302.             /* Update the subscription with the new 'published_in_tran_pub' value. */
  6303.             update sysmergearticles set published_in_tran_pub = @published_in_tran_pub_bit
  6304.                 where artid = @artid and pubid = @pubid
  6305.             IF @@ERROR <> 0
  6306.                 BEGIN
  6307.                     RAISERROR (14053, 16, -1)
  6308.                     goto UNDO
  6309.                 END
  6310.  
  6311.         END
  6312.  
  6313.     IF @bump_to_80=1
  6314.     BEGIN
  6315.         EXEC @retcode = sp_MSBumpupCompLevel @pubid, 40
  6316.         IF @@ERROR<>0 or @retcode<>0
  6317.             GOTO UNDO
  6318.     END
  6319.     /*
  6320.     ** Return succeed.
  6321.     */
  6322.     COMMIT TRAN
  6323.     RETURN (0)
  6324. UNDO:
  6325.     if @@TRANCOUNT > 0
  6326.     begin
  6327.         ROLLBACK TRANSACTION changemergearticle
  6328.         COMMIT TRANSACTION
  6329.     end
  6330.     return (1)
  6331. go
  6332. exec dbo.sp_MS_marksystemobject sp_changemergearticle
  6333. go
  6334.  
  6335. grant execute on dbo.sp_changemergearticle to public
  6336. go
  6337.  
  6338.  
  6339.  
  6340.  
  6341. raiserror('Creating procedure sp_MSadjustmergeidentity', 0,1)
  6342. GO
  6343.  
  6344. /*
  6345. ** When calling from the wrapper stored procedure, we make sure that there is one and
  6346. ** only one of the two input SP is NULL. Therefore, we do no checking here.
  6347. */
  6348.  
  6349. CREATE PROCEDURE sp_MSadjustmergeidentity 
  6350. @publication        sysname = NULL,
  6351. @tablename            sysname = NULL
  6352. AS
  6353.  
  6354. declare @db_name                sysname
  6355. declare @pubid                    uniqueidentifier
  6356. declare @next_seed                bigint
  6357. declare @pub_range                bigint
  6358. declare @objid                    int
  6359. declare @qualname                nvarchar(270)
  6360. declare @retcode                int
  6361. declare @user_name                sysname        
  6362. declare @range                    bigint
  6363. declare @current_max            bigint
  6364. declare @threshold                int
  6365. declare @distributor            sysname
  6366. declare @distribdb                sysname
  6367. declare @distproc                nvarchar(300)
  6368. declare @flag                    smallint
  6369. declare @c_max                    bigint
  6370. declare @n_seed                    bigint
  6371. declare @nickname                int
  6372. declare @identity_support        int
  6373. declare @artid                    uniqueidentifier
  6374. declare @identity_so_far        bigint
  6375. declare @tablelevel                bit
  6376.  
  6377. /*
  6378. ** Security Check
  6379. */
  6380. EXEC @retcode = dbo.sp_MSreplcheck_publish
  6381. IF @@ERROR <> 0 or @retcode <> 0
  6382.     return (1)
  6383.  
  6384. select @db_name=db_name()
  6385. select @pubid = newid()
  6386. select @objid = 0
  6387.  
  6388. if (@publication is NULL and @tablename is NULL) or 
  6389.      (@publication is not NULL and @tablename is not NULL)
  6390. begin
  6391.     raiserror('internal error on nullibility', 16, -1)
  6392.     return (1)
  6393. end
  6394.  
  6395. if @tablename is not NULL
  6396. begin
  6397.     select @tablelevel = 1
  6398.     select @objid = id from sysobjects where name=@tablename
  6399. end
  6400. else
  6401. begin
  6402.     select @tablelevel = 0
  6403.     select @pubid = pubid from sysmergepublications 
  6404.         where name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=@db_name
  6405. end
  6406.  
  6407. if exists (select * from sysmergearticles where identity_support<>0 and 
  6408.     ((pubid=@pubid and @tablelevel=0) or (@tablelevel=1 and objid=@objid)))
  6409. begin    
  6410.     EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb   = @distribdb OUTPUT
  6411.         IF @@ERROR <> 0 or @retcode <> 0
  6412.             return (1)
  6413.  
  6414.     declare one_article CURSOR LOCAL FAST_FORWARD FOR 
  6415.         select DISTINCT artid from sysmergearticles where identity_support<>0 and
  6416.             ((pubid=@pubid and @tablelevel=0) or (@tablelevel=1 and objid=@objid))
  6417.     open one_article
  6418.     fetch one_article into @artid
  6419.     while (@@fetch_status<>-1)
  6420.     begin
  6421.         select @objid=objid, @identity_support=identity_support from sysmergearticles 
  6422.                 where pubid=@pubid and artid=@artid
  6423.         select @tablename=object_name(@objid)
  6424.         select @user_name=user_name(uid) from sysobjects where id=@objid
  6425.         select @qualname=QUOTENAME(@user_name) + '.' + QUOTENAME(@tablename)
  6426.         select @next_seed=NULL, @range=NULL, @threshold=NULL --null if not being updated later
  6427.  
  6428.         select @current_max=0, @next_seed=0, @threshold=0, @range=0, @pub_range=0  --make them non-NULL
  6429.         SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MScheck_pub_identity'
  6430.         exec  @retcode=    @distproc @publisher=@@SERVERNAME,
  6431.                                       @publisher_db=@db_name,
  6432.                                       @tablename=@tablename,
  6433.                                       @range=@range OUTPUT,
  6434.                                       @current_max=@current_max OUTPUT,
  6435.                                       @threshold=@threshold OUTPUT,
  6436.                                       @next_seed = @next_seed OUTPUT,
  6437.                                       @pub_range=@pub_range OUTPUT
  6438.         if @retcode<>0 or @@ERROR<>0
  6439.             return (1)
  6440.  
  6441.         select @identity_so_far = IDENT_CURRENT(@tablename)
  6442.         select @flag=1
  6443.         if ident_incr(@tablename) < 0
  6444.             select @flag = -1
  6445.  
  6446.         /* To avoid div by zero errors, error out if pub_range is 0 */
  6447.         if @pub_range = 0
  6448.             begin
  6449.                 return 1
  6450.             end
  6451.     
  6452.         if @flag * 100 * (@identity_so_far - (@current_max + 1 - @pub_range))/@pub_range > @threshold
  6453.         begin
  6454.             select @c_max=@next_seed + @pub_range - 1
  6455.             select @n_seed=@next_seed + @pub_range
  6456.             SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSadjust_pub_identity'
  6457.             exec  @retcode=@distproc @publisher=@@SERVERNAME,
  6458.                                     @publisher_db=@db_name,
  6459.                                     @tablename=@tablename,
  6460.                                     @current_max=@c_max,
  6461.                                     @next_seed = @n_seed
  6462.             if @retcode<>0 or @@ERROR<>0
  6463.                 return (1)
  6464.             exec @retcode=sp_MSreseed @objid, @next_seed, @pub_range, 1
  6465.             if @@ERROR <> 0 or @retcode<>0
  6466.                 begin
  6467.                     raiserror(21197, 16, -1)
  6468.                     return (1)
  6469.                 end
  6470.             select @next_seed=@next_seed + @pub_range
  6471.         end
  6472.     fetch next from one_article into @artid
  6473.     end
  6474. end
  6475. else
  6476. begin
  6477.     raiserror(21295, 16, -1, @publication)
  6478.     return (1)
  6479. end
  6480. GO
  6481. exec dbo.sp_MS_marksystemobject sp_MSadjustmergeidentity 
  6482. go
  6483.  
  6484. /*
  6485. ** This SP is called to see if merge publication is still allowed for current database.
  6486. ** Merge publishing is disallowed if current DB subscribes as local/anonymous subscriber
  6487. ** 1 means OK, 0 for publication not allowed.
  6488. */
  6489. raiserror('Creating procedure sp_helpallowmerge_publication', 0,1)
  6490. GO
  6491.  
  6492. CREATE PROCEDURE sp_helpallowmerge_publication 
  6493. AS
  6494. declare @srvid      int
  6495. declare @db_name    sysname
  6496.  
  6497. /* Select srvid = 0 for the local server name */
  6498. select @srvid = 0
  6499. select @db_name = db_name()
  6500. if exists (select name from sysobjects where name='sysmergesubscriptions')
  6501.     if exists (select priority from sysmergesubscriptions where db_name=@db_name and srvid = @srvid and priority=0)
  6502.         begin
  6503.             select 0
  6504.             RETURN (0)
  6505.         end
  6506. select 1
  6507. GO
  6508. exec dbo.sp_MS_marksystemobject sp_helpallowmerge_publication 
  6509. go
  6510.  
  6511. raiserror('Creating procedure sp_helpmergearticle', 0,1)
  6512. GO
  6513.  
  6514. CREATE PROCEDURE sp_helpmergearticle (
  6515.     @publication sysname = '%',   /* The publication name */
  6516.     @article sysname = '%'        /* The article name */
  6517.     ) AS
  6518.  
  6519.     SET NOCOUNT ON
  6520.  
  6521.     /*
  6522.     ** Declarations.
  6523.     */
  6524.     declare @retcode            int
  6525.     /*
  6526.     ** Create a temporary table to hold all information.
  6527.     */
  6528.     declare @helpmergearticle TABLE
  6529.         (
  6530.             id                      int             identity NOT NULL,
  6531.             name                    sysname         collate database_default not null,
  6532.             source_owner            sysname         collate database_default not null,
  6533.             source_object           sysname         collate database_default not null,      /* converted from objid */
  6534.             sync_object_owner       sysname         collate database_default null,
  6535.             sync_object             sysname         collate database_default null,      /* converted from sync_objid */
  6536.             description             nvarchar(255)   collate database_default null,
  6537.             status                  tinyint         NULL,
  6538.             creation_script         nvarchar(255)   collate database_default null,
  6539.             conflict_table          nvarchar(270)   collate database_default null,
  6540.             article_resolver        nvarchar(255)   collate database_default null,
  6541.             subset_filterclause     nvarchar(1000)  collate database_default null,
  6542.             pre_creation_command    tinyint         NULL, 
  6543.             schema_option           binary(8)       NULL,
  6544.             type                    smallint        NULL,
  6545.             column_tracking         int             NULL,
  6546.             resolver_info           nvarchar(255)   collate database_default null,
  6547.             vertical_partition        bit                NULL,
  6548.             destination_owner        sysname            collate database_default null,
  6549.             identity_support        int                NULL,
  6550.             pub_identity_range        bigint            NULL,
  6551.             identity_range            bigint            NULL,
  6552.             threshold                int                NULL,
  6553.             verify_resolver_signature int            NULL,
  6554.             destination_object      sysname         collate database_default not null,
  6555.             allow_interactive_resolver    int            NULL,
  6556.             fast_multicol_updateproc    int            NULL,
  6557.             check_permissions        int                NULL
  6558.         )
  6559.         
  6560.     /*
  6561.     ** Running sp_help is OK from everywhere, whether enabled for publishing or not
  6562.     */
  6563.     IF not exists (select * from sysobjects where name= 'sysmergesubscriptions')
  6564.         RETURN (0)
  6565.  
  6566.     /*
  6567.     ** Parameter Check:  @publication.
  6568.     ** Check to make sure that the publication exists, that it conforms
  6569.     ** to the rules for identifiers, and that it isn't NULL.
  6570.     */
  6571.  
  6572.     if @publication IS NULL
  6573.         BEGIN
  6574.             RAISERROR (14043, 16, -1, '@publication')
  6575.             RETURN (1)
  6576.         END
  6577.  
  6578.        if @publication <> '%'
  6579.         BEGIN
  6580.             if NOT EXISTS (select pubid 
  6581.                                 FROM sysmergepublications
  6582.                                 WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name())
  6583.                 BEGIN
  6584.                     RAISERROR (20026, 16, -1, @publication)
  6585.                     RETURN (1)
  6586.                 END
  6587.  
  6588.         END
  6589.  
  6590.     /*
  6591.     ** Parameter Check:  @article.
  6592.     ** Check to make sure that the article exists, that it conforms
  6593.     ** to the rules for identifiers, and that it isn't NULL.
  6594.     */
  6595.  
  6596.     if @article IS NULL
  6597.         BEGIN
  6598.             RAISERROR (14043, 16, -1, '@article')
  6599.             RETURN (1)
  6600.         END
  6601.  
  6602.     if @article <> '%'
  6603.         BEGIN
  6604.             if NOT EXISTS (select *
  6605.                            FROM sysmergeextendedarticlesview
  6606.                            WHERE name = @article
  6607.                            AND pubid IN (select pubid 
  6608.                                          FROM sysmergepublications 
  6609.                                          WHERE name like @publication  
  6610.                                             and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()))
  6611.                 BEGIN
  6612.                     RAISERROR (20027, 16, -1, @article)
  6613.                     RETURN (1)
  6614.                 END
  6615.  
  6616.         END
  6617.  
  6618.     
  6619.     INSERT INTO @helpmergearticle 
  6620.         (name, 
  6621.         source_owner,
  6622.         source_object, 
  6623.         sync_object_owner,
  6624.         sync_object, 
  6625.         description, 
  6626.         status, 
  6627.         creation_script, 
  6628.         conflict_table, 
  6629.         pre_creation_command, 
  6630.         schema_option, 
  6631.         type, 
  6632.         column_tracking, 
  6633.         article_resolver, 
  6634.         subset_filterclause,
  6635.         resolver_info,
  6636.         vertical_partition,
  6637.         destination_owner,
  6638.         identity_support,
  6639.         pub_identity_range,
  6640.         identity_range,
  6641.         threshold,
  6642.         verify_resolver_signature,
  6643.         destination_object,
  6644.         allow_interactive_resolver,
  6645.         fast_multicol_updateproc,
  6646.         check_permissions)
  6647.     select  art.name,
  6648.             users1.name,
  6649.             objects.name, 
  6650.             users2.name,
  6651.             syncobjects.name, 
  6652.             art.description, 
  6653.             art.status, 
  6654.             art.creation_script, 
  6655.             art.conflict_table, 
  6656.             art.pre_creation_command,
  6657.             art.schema_option, 
  6658.             case 
  6659.                 when objectproperty(art.objid, 'IsSchemaBound') = 1 and art.type <> 0x80 then 0x0100 | convert(smallint, art.type) 
  6660.                 else convert(smallint, ISNULL(art.type,0x0a)) 
  6661.                 end,
  6662.             art.column_tracking, 
  6663.             art.article_resolver, 
  6664.             art.subset_filterclause,
  6665.             art.resolver_info,
  6666.             art.vertical_partition,
  6667.             art.destination_owner,
  6668.             art.identity_support,
  6669.             ABS(ir.pub_range),
  6670.             ABS(ir.range),
  6671.             ir.threshold,
  6672.             art.verify_resolver_signature,
  6673.             art.destination_object,
  6674.             art.allow_interactive_resolver,
  6675.             art.fast_multicol_updateproc,
  6676.             art.check_permissions
  6677.     FROM    sysmergeextendedarticlesview art left outer join MSrepl_identity_range ir on art.objid=ir.objid 
  6678.             inner join sysmergepublications pubs on art.pubid = pubs.pubid
  6679.             inner join sysobjects objects on objects.id = art.objid
  6680.             left outer join sysobjects syncobjects on art.sync_objid = syncobjects.id 
  6681.             inner join sysusers users1 on objects.uid = users1.uid
  6682.             left outer join sysusers users2 on syncobjects.uid = users2.uid
  6683.             WHERE art.name LIKE @article
  6684.                 AND pubs.name LIKE @publication
  6685.                 AND UPPER(pubs.publisher) = UPPER(@@servername)
  6686.                 AND pubs.publisher_db = db_name()
  6687.                 and (1 = {fn ISPALUSER(pubs.pubid)} or
  6688.                      1 = is_member('replmonitor'))
  6689.             order by art.nickname desc
  6690.  
  6691.     select * from @helpmergearticle 
  6692.     RETURN (0)
  6693. go
  6694. exec dbo.sp_MS_marksystemobject sp_helpmergearticle 
  6695. go
  6696.  
  6697. grant execute on dbo.sp_helpmergearticle to public
  6698. go
  6699.  
  6700. raiserror('Creating procedure sp_dropmergearticle', 0,1)
  6701. GO
  6702.  
  6703. CREATE PROCEDURE sp_dropmergearticle(
  6704.     @publication sysname,     /* The publication name */
  6705.     @article sysname,         /* The article name */
  6706.     @ignore_distributor bit = 0,
  6707.     @reserved bit = 0,
  6708.     @force_invalidate_snapshot bit = 0
  6709.     ) AS
  6710.  
  6711.     set nocount on
  6712.     /*
  6713.     ** Declarations.
  6714.     */
  6715.  
  6716.     declare @db_name                sysname
  6717.     declare @cmd                    nvarchar(255)
  6718.     declare @artid                  uniqueidentifier
  6719.     declare @snapshot_ready            int
  6720.     declare @objid                  int
  6721.     declare @pubid                  uniqueidentifier
  6722.     declare @pubidstr               nvarchar(38)
  6723.     declare @merge_pub_object_bit   int
  6724.     declare @unpublish_bit          int
  6725.     declare @retcode                int
  6726.     declare @replinfo               int
  6727.     declare @dbname                 sysname
  6728.     declare @distributor            sysname
  6729.     declare @distribdb              sysname
  6730.     declare @distproc               nvarchar(300)
  6731.     declare @object_name            sysname
  6732.     declare @uid                    smallint
  6733.     declare @owner                  sysname
  6734.     declare @qualified_name         nvarchar(270)
  6735.     declare @filterid                int
  6736.     declare @proc_name                sysname
  6737.     declare @implicit_transaction    int
  6738.     declare @close_cursor_at_commit int
  6739.     declare @sync_objid     int
  6740.     declare @view_type        int
  6741.     declare @type           tinyint
  6742.     declare @allow_anonymous    int
  6743.     select @close_cursor_at_commit = 0
  6744.     select @implicit_transaction = 0
  6745.     /*
  6746.     ** Save setting values first before changing them
  6747.     */
  6748.     IF (@reserved = 0)
  6749.     BEGIN
  6750.         SELECT @implicit_transaction = @@options & 2
  6751.         SELECT @close_cursor_at_commit = @@options & 4
  6752.         SET IMPLICIT_TRANSACTIONS OFF
  6753.         SET CURSOR_CLOSE_ON_COMMIT OFF
  6754.     END
  6755.     
  6756.     /*
  6757.     ** Initializations.
  6758.     */
  6759.     -- merge uses bit 8 in replinfo
  6760.     select @merge_pub_object_bit    = 128  
  6761.     select @unpublish_bit = ~@merge_pub_object_bit
  6762.  
  6763.  
  6764.     /*
  6765.     ** Security Check
  6766.     */
  6767.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  6768.     IF @@ERROR <> 0 or @retcode <> 0
  6769.         return (1)
  6770.  
  6771.     /* make sure current database is enabled for merge replication */
  6772.     exec @retcode=dbo.sp_MSCheckmergereplication
  6773.     if @@ERROR<>0 or @retcode<>0
  6774.         return (1)
  6775.         
  6776.     select @pubid = pubid, @snapshot_ready=snapshot_ready, @allow_anonymous=allow_anonymous FROM sysmergepublications 
  6777.         WHERE name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  6778.     if @pubid is NULL
  6779.         BEGIN
  6780.             RAISERROR (20026, 16, -1, @publication)
  6781.             RETURN (1)
  6782.         END
  6783.  
  6784.     /*
  6785.     ** Once snapshot is ready, do not allow dropping an article except
  6786.     ** when the article is schema-only.
  6787.     */
  6788.     if @snapshot_ready>0 and 
  6789.        (@allow_anonymous=1 or 
  6790.        exists (select * from sysmergesubscriptions 
  6791.                 where pubid=@pubid and subid<>pubid and status=1)) and
  6792.        not exists (select * from sysmergeschemaarticles 
  6793.                     where pubid = @pubid and name = @article)  
  6794.         begin
  6795.             RAISERROR (21338, 16, -1, @article, @publication)
  6796.             RETURN (1)
  6797.         end
  6798.  
  6799.     if @snapshot_ready>0
  6800.         begin
  6801.             if @force_invalidate_snapshot = 0
  6802.                 begin
  6803.                     raiserror(21379, 16, -1, @article, @publication)
  6804.                     return (1)
  6805.                 end
  6806.             update sysmergepublications set snapshot_ready=2 where pubid=@pubid
  6807.             if @@ERROR<>0
  6808.                 return (1)
  6809.         end
  6810.     
  6811.     
  6812.     set @pubidstr = '''' + convert(nchar(36), @pubid) + ''''
  6813.  
  6814.     /*
  6815.     ** Parameter Check:  @article.
  6816.     ** If the @article is 'all', drop all articles for the specified
  6817.     ** publication (@publication).
  6818.     */
  6819.  
  6820.     if LOWER(@article) = 'all'
  6821.         BEGIN
  6822.             declare hC CURSOR LOCAL FAST_FORWARD FOR select DISTINCT name FROM sysmergeextendedarticlesview WHERE pubid=@pubid FOR READ ONLY
  6823.             
  6824.             OPEN hC
  6825.             FETCH hC INTO @article
  6826.             WHILE (@@fetch_status <> -1)
  6827.                 BEGIN
  6828.                     EXECUTE dbo.sp_dropmergearticle @publication, @article,
  6829.                         @ignore_distributor = @ignore_distributor,
  6830.                         @reserved = 1
  6831.                     FETCH hC INTO @article
  6832.                 END
  6833.             CLOSE hC
  6834.             DEALLOCATE hC
  6835.             RETURN (0)
  6836.         END
  6837.  
  6838.     /*
  6839.     ** Parameter Check: @article.
  6840.     ** The @article name must conform to the rules for identifiers.
  6841.     */
  6842.  
  6843.     if @article IS NULL
  6844.         BEGIN
  6845.             RAISERROR (14043, 16, -1, '@article')
  6846.             RETURN (1)
  6847.         END
  6848.  
  6849.     /*
  6850.     ** Parameter Check: @publication.
  6851.     ** The @publication name must conform to the rules for identifiers.
  6852.     */
  6853.  
  6854.     if @publication IS NULL
  6855.         BEGIN
  6856.             RAISERROR (14043, 16, -1, '@publication')
  6857.             RETURN (1)
  6858.         END
  6859.  
  6860.     /*
  6861.     ** Ascertain the existence of the article.
  6862.     */
  6863.     select @type = NULL
  6864.     select @type = type ,
  6865.            @artid = artid
  6866.       from sysmergeextendedarticlesview 
  6867.      where name = @article
  6868.        and pubid = @pubid
  6869.  
  6870.     if @type is NULL
  6871.         begin
  6872.             raiserror (20027, 16, -1, @article)
  6873.             return (1)
  6874.         end
  6875.  
  6876.     -- if all articles are to be dropped, ignore this checking.
  6877.     if @reserved=0 and exists (select * from sysmergesubsetfilters where pubid=@pubid and join_articlename=@article)
  6878.         begin
  6879.             raiserror(21421, 16, -1, @article)
  6880.             return (1)
  6881.         end
  6882.  
  6883.     /*
  6884.     **  Delete article from sysmergearticles and clear publish bit in
  6885.     **  sysobjects.
  6886.     */
  6887.  
  6888.     begin tran 
  6889.     save TRAN dropmergearticle
  6890.         /*
  6891.         ** Remove the corresponding rows from sysmergeschemachange
  6892.         */
  6893.         DELETE FROM sysmergeschemachange WHERE artid = @artid AND pubid = @pubid
  6894.         if @@ERROR <> 0
  6895.             goto FAILURE
  6896.         /*
  6897.         ** Removing a schema only article is a lot simpler than 
  6898.         ** removing a table article so a different code path is created
  6899.         ** to handle this.  
  6900.         */
  6901.         if @type in (0x20, 0x40, 0x80)
  6902.             begin
  6903.             /*
  6904.             ** Retrieve the object id of the underlying proc or view object.
  6905.             */
  6906.             select @objid = objid
  6907.                 from sysmergeschemaarticles where name = @article and pubid = @pubid
  6908.                 
  6909.             /*
  6910.             ** Remove the corresponding record in sysmergeschemaarticles
  6911.             */
  6912.             delete sysmergeschemaarticles where name = @article and pubid = @pubid
  6913.  
  6914.             /*
  6915.             ** If this is the last schema only article for the underlying 
  6916.             ** view or proc object, unmark the 0x200 bit in sysobject.replinfo  
  6917.             */
  6918.             if not exists (select * from sysmergeschemaarticles 
  6919.                             where objid = @objid)
  6920.                 begin
  6921.                 select @merge_pub_object_bit = 512
  6922.                 select @unpublish_bit = ~(@merge_pub_object_bit)
  6923.                 if not exists (select * from sysobjects 
  6924.                                 where name = 'sysschemaarticles')
  6925.                     begin   
  6926.                     update sysobjects set replinfo = (@unpublish_bit & replinfo) where id = @objid
  6927.                     end    
  6928.                 else if  not exists (select * from sysschemaarticles 
  6929.                                       where objid = @objid) 
  6930.                     begin   
  6931.                     update sysobjects set replinfo = (@unpublish_bit & replinfo) where id = @objid
  6932.                     end    
  6933.                 end
  6934.             end
  6935.         else 
  6936.             begin
  6937.             /*
  6938.             ** Retrieve the object id of the underlying table.
  6939.             */
  6940.             select @sync_objid = sync_objid, @view_type = view_type, @artid = artid, @objid = objid
  6941.                 from sysmergearticles where name = @article AND pubid = @pubid
  6942.             select @replinfo = replinfo, @object_name=name, @owner= user_name(uid) from sysobjects where id = @objid
  6943.         
  6944.             /*
  6945.             ** If this is the last article that refers to the base table, drop the 
  6946.             ** triggers and stored procs 
  6947.             */
  6948.             if NOT exists (select * from sysmergearticles WHERE artid = @artid AND pubid <> @pubid)
  6949.                 begin
  6950.                 /*
  6951.                 ** Cleanup the triggers and stored procs
  6952.                 */
  6953.                 EXECUTE @retcode = dbo.sp_MSarticlecleanup @artid = @artid, @pubid = @pubid
  6954.                 if @@ERROR <> 0 OR @retcode <> 0
  6955.                     BEGIN
  6956.                         GOTO FAILURE
  6957.                     END
  6958.             
  6959.                 /*
  6960.                 ** Clear the replication bit in sysobjects. Now merge and transactional level
  6961.                 ** uses different replication bit, checking transactional level is not needed.
  6962.                 */
  6963.  
  6964.                 select @qualified_name = (QUOTENAME(@owner) + '.' + QUOTENAME(@object_name))
  6965.                 exec @retcode = dbo.sp_replupdateschema @qualified_name
  6966.                 if @@ERROR <> 0 OR @retcode <> 0
  6967.                     BEGIN
  6968.                         GOTO FAILURE
  6969.                     END
  6970.             
  6971.                 update sysobjects set replinfo = (replinfo & @unpublish_bit) where id = @objid
  6972.  
  6973.                 IF @@ERROR <> 0
  6974.                     goto FAILURE
  6975.                 end             
  6976.             else
  6977.                 begin
  6978.                 /* Always drop the article proc's they are not shared among publications */
  6979.                 EXECUTE @retcode = dbo.sp_MSdroparticleprocs @artid = @artid, @pubid = @pubid
  6980.                 if @@ERROR <> 0 OR @retcode <> 0
  6981.                     begin
  6982.                         goto FAILURE
  6983.                     end
  6984.                 /* If the article's has a temporary ( view type = 2) or a permanent view (view_type = 1 ) drop the sync object */
  6985.                 if (@view_type = 1 OR @view_type = 2)
  6986.                     begin
  6987.                     declare @viewname sysname
  6988.                     select @viewname = sysobjects.name from sysobjects where 
  6989.                         ObjectProperty (sysobjects.id, 'IsView') = 1 
  6990.                         and ObjectProperty (sysobjects.id, 'IsMSShipped') = 1 
  6991.                         and sysobjects.id = @sync_objid
  6992.                     if @viewname IS NOT NULL
  6993.                         begin
  6994.                             set @viewname = QUOTENAME(@viewname)
  6995.                             exec ('drop view ' + @viewname)
  6996.                             if @@ERROR<>0  GOTO FAILURE
  6997.                         end
  6998.                     end
  6999.                 end
  7000.             /*
  7001.             ** Remove the row from sysmergearticles.
  7002.             */
  7003.             DELETE FROM sysmergearticles WHERE artid = @artid AND pubid = @pubid
  7004.             if @@ERROR <> 0
  7005.                 BEGIN
  7006.                     GOTO FAILURE
  7007.                 END
  7008.  
  7009.  
  7010.             /* delete all the filter components that are defined upon the designated article */
  7011.             select @filterid = min(join_filterid) from sysmergesubsetfilters where
  7012.                 artid = @artid AND pubid = @pubid
  7013.             while (@filterid is not null)
  7014.                 begin
  7015.                 select @proc_name = quotename(expand_proc) from sysmergesubsetfilters where
  7016.                     artid = @artid AND pubid = @pubid and join_filterid = @filterid
  7017.  
  7018.                 if (@proc_name IS NOT NULL) and exists (select * from sysobjects where
  7019.                     name = @proc_name and type = 'P')
  7020.                     begin
  7021.                         exec ('drop proc ' + @proc_name)
  7022.                         IF @@ERROR <> 0
  7023.                         goto FAILURE
  7024.                     end
  7025.                 delete from sysmergesubsetfilters where
  7026.                     artid = @artid AND pubid = @pubid and join_filterid = @filterid
  7027.                 IF @@ERROR <> 0
  7028.                        goto FAILURE
  7029.                 select @filterid = min(join_filterid) from sysmergesubsetfilters where
  7030.                     artid = @artid AND pubid = @pubid
  7031.                 end
  7032.  
  7033.  
  7034.             /*
  7035.             ** set the pub type to subset or full as appropriate
  7036.             */
  7037.             execute @retcode = dbo.sp_MSsubsetpublication @publication
  7038.             if @@ERROR <> 0 or @retcode <> 0 
  7039.                 RETURN (1)
  7040.                 
  7041.             /*
  7042.             ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
  7043.             */
  7044.             if @ignore_distributor = 0
  7045.                 begin
  7046.                 /*
  7047.                 ** Get distribution server information for remote RPC call.
  7048.                 */
  7049.                 EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
  7050.                    @distribdb   = @distribdb OUTPUT
  7051.                 IF @@ERROR <> 0 or @retcode <> 0
  7052.                     BEGIN
  7053.                         goto FAILURE
  7054.                     END
  7055.  
  7056.                 SELECT @dbname =  DB_NAME()
  7057.         
  7058.                 SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + 
  7059.                     '.dbo.sp_MSdrop_article'
  7060.                 EXECUTE @retcode = @distproc
  7061.                     @publisher = @@SERVERNAME,
  7062.                     @publisher_db = @dbname,
  7063.                     @publication = @publication,
  7064.                     @article = @article
  7065.                       
  7066.                 IF @@ERROR <> 0 or @retcode <> 0
  7067.                     BEGIN
  7068.                         goto FAILURE
  7069.                     END
  7070.                 end
  7071.             end            
  7072.     
  7073.     COMMIT TRAN
  7074.     /*
  7075.     ** Set back original settings
  7076.     */    
  7077.     IF @reserved = 0
  7078.     BEGIN
  7079.         IF @implicit_transaction <>0 
  7080.             SET IMPLICIT_TRANSACTIONS ON
  7081.         IF @close_cursor_at_commit <>0 
  7082.             SET CURSOR_CLOSE_ON_COMMIT ON
  7083.     END
  7084.     RETURN (0)
  7085. FAILURE:
  7086.     RAISERROR (14047, 16, -1, @article)
  7087.     if @@TRANCOUNT > 0
  7088.     begin
  7089.         ROLLBACK TRANSACTION dropmergearticle
  7090.         COMMIT TRANSACTION
  7091.     end
  7092.     /*
  7093.     ** Set back original settings
  7094.     */    
  7095.     IF @reserved = 0
  7096.     BEGIN
  7097.         IF @implicit_transaction <>0 
  7098.             SET IMPLICIT_TRANSACTIONS ON
  7099.         IF @close_cursor_at_commit <>0 
  7100.             SET CURSOR_CLOSE_ON_COMMIT ON
  7101.     END
  7102.     RETURN (1)
  7103. go
  7104. exec dbo.sp_MS_marksystemobject sp_dropmergearticle
  7105. go
  7106.  
  7107. grant execute on dbo.sp_dropmergearticle to public
  7108. go
  7109.  
  7110.  
  7111. raiserror('Creating procedure sp_addmergepublication', 0,1)
  7112. GO
  7113.  
  7114. create procedure sp_addmergepublication (
  7115.     @publication            sysname,                /* Publication name */
  7116.     @description            nvarchar(255)= NULL,            /* Publication description */
  7117.     @retention              int         = 14,           /* Retention period of 14 days */
  7118.     @sync_mode              nvarchar(10) = 'native',    /* (bcp)native, (bcp)character */
  7119.     @allow_push             nvarchar(5)  = 'true',      /* Pulication allows push subscriptions */
  7120.     @allow_pull             nvarchar(5)  = 'true',      /* Pulication allows pull subscriptions*/
  7121.     @allow_anonymous        nvarchar(5)  = 'false',     /* Pulication allows anonymous subscriptions */
  7122.     @enabled_for_internet   nvarchar(5)     = 'false',  /* Pulication is enabled for internet */
  7123.     @centralized_conflicts  nvarchar(5)  = 'true',      /* Conflict records stored at publisher : true or false */
  7124.     @dynamic_filters        nvarchar(5) = 'false',      /* Will publication be filtered on dynamic clause? */
  7125.     @snapshot_in_defaultfolder      nvarchar(5) = 'true',       /* Will keep a copy of the snapshot files to the default location if an alternate folder is specified */
  7126.     @alt_snapshot_folder    nvarchar(255) = NULL,       /* Alternate folder for putting the snapshot file for this publication */
  7127.     @pre_snapshot_script    nvarchar(255) = NULL,        /* Pre snapshot commands */
  7128.     @post_snapshot_script   nvarchar(255) = NULL,        /* Post snapshot commands */
  7129.     @compress_snapshot      nvarchar(5) = 'false',        /* Snapshot compression */
  7130.     @ftp_address            sysname = NULL,                /* Post 7.0 FTP Properties */
  7131.     @ftp_port               int = 21,                    /* Post 7.0 FTP Properties */
  7132.     @ftp_subdirectory       nvarchar(255) = NULL,        /* Post 7.0 FTP Properties */
  7133.     @ftp_login              sysname = N'anonymous',        /* Post 7.0 FTP Properties */
  7134.     @ftp_password           sysname = NULL,                /* Post 7.0 FTP Properties */
  7135.     @conflict_retention        int = 14,                    /* Conflict retention period */
  7136.     @keep_partition_changes nvarchar(5) = 'false',        /* Optimized Partition Updates/Deletes */
  7137.     @allow_subscription_copy    nvarchar(5) = 'false',    /* Allow the subscription to be copied */
  7138.     @allow_synctoalternate        nvarchar(5) = 'false',    /* Allow the subscription to be synchronize to alternate partners */
  7139.     @validate_subscriber_info    nvarchar(500) = NULL,    /* Should we validate that subscriber is using right params? */
  7140.     @add_to_active_directory    nvarchar(5) = 'false',
  7141.     @max_concurrent_merge    int = 0,                     /* value of 0 means no such limit exists */
  7142.     @max_concurrent_dynamic_snapshots int = 0           /* Maximum number of concurrent dynamic snapshot sessions */
  7143.     ) as
  7144.  
  7145.     set nocount on
  7146.  
  7147.     /*
  7148.     ** Declarations.
  7149.     */
  7150.     
  7151.     declare @retcode                    int         /* return code value for procedure execution */
  7152.     declare @push                       tinyint     /* subscription type is push */
  7153.     declare @statid                     tinyint     /* status id based on @status */
  7154.     declare @sync_modeid                tinyint     /* sync mode id based on @sync_mode */
  7155.     declare @global                     tinyint     /* subscriber type of loop-back subscription */
  7156.     declare @db_name                    sysname     /* database name */
  7157.     declare @srvid                      int         /* Server ID */
  7158.     declare @nickname                   int         /* replica nickname */
  7159.     declare @tranpublish_bit            smallint    /* online publish bit (flag) in sysdatabases */
  7160.     declare @mergepublish_bit           smallint    /* merge publish bit (flag) in sysdatabases */
  7161.     declare @found                      int         /* flag indicating if publication is found */
  7162.     declare @pubid                      uniqueidentifier    /* Publication identifier */
  7163.     declare @allow_push_id              bit
  7164.     declare @allow_pull_id              bit
  7165.     declare @allow_anonymous_id         bit
  7166.     declare @dynamic_filters_id         bit         
  7167.     declare @allow_subscription_copy_id bit         
  7168.     declare @allow_synctoalternate_id     bit         
  7169.     declare @enabled_for_internet_id    bit
  7170.     declare @centralized_conflicts_id   bit
  7171.     declare @priority                   real        
  7172.     declare @automatic                  tinyint     
  7173.     declare @false                      bit
  7174.     declare @true                       bit
  7175.     declare @distributor                sysname
  7176.     declare @distproc                   nvarchar(300)
  7177.     declare @distribdb                  sysname
  7178.     declare @distpubid                  int
  7179.     declare @full                       int
  7180.     declare @snapshot_in_defaultfolder_bit      bit
  7181.     declare @compress_snapshot_bit      bit
  7182.     declare @keep_before_values_int           int
  7183.     declare @enc_ftp_password           nvarchar(524)
  7184.     declare @ad_guidname                sysname
  7185.     declare @schemaversion              int 
  7186.     declare @schemaguid                 uniqueidentifier
  7187.     declare @schematype                 int
  7188.     declare @schematext                 nvarchar(2000)
  7189.     declare @artid                        uniqueidentifier
  7190.     declare @distservername                sysname
  7191.     declare @backward_comp_level        int
  7192.     
  7193.     /* make sure current database is enabled for merge replication */
  7194.     exec @retcode=dbo.sp_MSCheckmergereplication
  7195.     if @@ERROR<>0 or @retcode<>0
  7196.         return (1)
  7197.  
  7198.     /*
  7199.     ** Initializations
  7200.     */
  7201.     select @backward_comp_level    = 10 --that of 7.0 RTM
  7202.     
  7203.     select @mergepublish_bit    = 4 
  7204.     select @tranpublish_bit     = 1
  7205.     select @priority            = 100.0
  7206.     select @automatic           = 1     /* Const: synchronization type 'automatic' */
  7207.     select @true                = 1
  7208.     select @false               = 0
  7209.     select @full                = 0     /* Const: publication type 'full' */
  7210.  
  7211.     /*
  7212.     ** Set the status to Active (1)
  7213.     */
  7214.     select @statid      = 1
  7215.     select @global      = 1
  7216.     select @push        = 0
  7217.     select @db_name     = DB_NAME()
  7218.     select @ad_guidname = NULL
  7219.  
  7220.     /*
  7221.     ** Security Check
  7222.     */
  7223.  
  7224.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  7225.     IF @@ERROR <> 0 or @retcode <> 0
  7226.         return (1)
  7227.  
  7228.     /*
  7229.     ** Parameter Check: @publication.
  7230.     ** The @publication name must conform to the rules for identifiers,
  7231.     ** and must not be the keyword 'all'.
  7232.     */
  7233.     if @publication is NULL
  7234.         begin
  7235.             raiserror (14043, 16, -1, '@publication')
  7236.             return (1)
  7237.         end
  7238.  
  7239.     exec @retcode = dbo.sp_MSreplcheck_name @publication
  7240.     if @@ERROR <> 0 or @retcode <> 0
  7241.         return(1)
  7242.        
  7243.     if LOWER (@publication) = 'all'
  7244.         begin
  7245.             raiserror (14034, 16, -1)
  7246.             return (1)
  7247.         end
  7248.         
  7249.     if @max_concurrent_merge<0
  7250.         begin
  7251.             raiserror(21402, 16, -1, '@max_concurrent_merge')
  7252.             return (1)
  7253.         end
  7254.  
  7255.     /*
  7256.     ** Parameter Check: @retention.
  7257.     */
  7258.         
  7259.     if @retention is not NULL and @retention<0 
  7260.         begin
  7261.             raiserror(20050, 16, -1, 0)
  7262.             return(1)
  7263.         end
  7264.  
  7265.     if @retention is NULL
  7266.         select @retention = 0
  7267.  
  7268.     /*
  7269.     ** Parameter Check: @conflict_retention.
  7270.     */
  7271.         
  7272.     if @conflict_retention is not NULL and @conflict_retention<0 
  7273.         begin
  7274.             raiserror(20050, 16, -1, 0)
  7275.             return(1)
  7276.         end
  7277.  
  7278.     /*
  7279.     ** if it is NULL, use the default value of 14 days.
  7280.     */
  7281.     if @conflict_retention is NULL 
  7282.         select @conflict_retention = 14
  7283.  
  7284.     /*
  7285.     ** Parameter Check: @sync_mode.
  7286.     ** Make sure that the sync_mode is one of the following:
  7287.     **
  7288.     **  id  sync_mode
  7289.     **  ==  ==========
  7290.     **   0  (bcp)native
  7291.     **   1  (bcp)character
  7292.     */
  7293.     
  7294.     if LOWER(@sync_mode collate SQL_Latin1_General_CP1_CS_AS)='portable' select @sync_mode='character'
  7295.  
  7296.     if LOWER(@sync_mode collate SQL_Latin1_General_CP1_CS_AS) is NULL OR LOWER(@sync_mode collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('bcp native', 'bcp character', 'native', 'character')
  7297.         begin
  7298.             raiserror (20076, 16, -1)
  7299.             return (1)
  7300.         end
  7301.  
  7302.     if LOWER(@sync_mode collate SQL_Latin1_General_CP1_CS_AS) = 'native' or 
  7303.        LOWER(@sync_mode collate SQL_Latin1_General_CP1_CS_AS)='bcp native' 
  7304.         select @sync_modeid = 0
  7305.     else 
  7306.         select @sync_modeid = 1
  7307.  
  7308.     /*
  7309.     ** Parameter Check:  @allow_push.
  7310.     */
  7311.  
  7312.     if @allow_push IS NULL OR LOWER(@allow_push collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  7313.         BEGIN
  7314.             RAISERROR (14148, 16, -1, '@allow_push')
  7315.             RETURN (1)
  7316.         END
  7317.  
  7318.     if LOWER(@allow_push collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
  7319.         select @allow_push_id = 1
  7320.     else 
  7321.         select @allow_push_id = 0
  7322.  
  7323.     /*
  7324.     ** Parameter Check:  @allow_pull.
  7325.     */
  7326.  
  7327.     if @allow_pull IS NULL OR LOWER(@allow_pull collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  7328.         BEGIN
  7329.             RAISERROR (14148, 16, -1, '@allow_pull')
  7330.             RETURN (1)
  7331.         END
  7332.     if LOWER(@allow_pull collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
  7333.         select @allow_pull_id = 1
  7334.     else 
  7335.         select @allow_pull_id = 0
  7336.  
  7337.     /*
  7338.     ** Parameter Check:  @allow_anonymous.
  7339.     */
  7340.  
  7341.     if @allow_anonymous IS NULL OR LOWER(@allow_anonymous collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  7342.         BEGIN
  7343.             RAISERROR (14148, 16, -1, '@allow_anonymous')
  7344.             RETURN (1)
  7345.         END
  7346.     if LOWER(@allow_anonymous collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
  7347.         select @allow_anonymous_id = 1
  7348.     else 
  7349.         select @allow_anonymous_id = 0
  7350.  
  7351.     /*
  7352.     ** Parameter Check:  @enabled_for_internet.
  7353.     */
  7354.  
  7355.     IF @enabled_for_internet IS NULL OR LOWER(@enabled_for_internet collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  7356.         BEGIN
  7357.             RAISERROR (14148, 16, -1, '@enabled_for_internet')
  7358.             RETURN (1)
  7359.         END
  7360.  
  7361.     IF LOWER(@enabled_for_internet collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
  7362.         SELECT @enabled_for_internet_id = 1
  7363.     ELSE 
  7364.         SELECT @enabled_for_internet_id = 0
  7365.  
  7366.     /*
  7367.     ** Parameter Check:  @centralized_conflicts.
  7368.     */
  7369.  
  7370.     if @centralized_conflicts IS NULL OR LOWER(@centralized_conflicts collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  7371.         BEGIN
  7372.             RAISERROR (14148, 16, -1, '@centralized_conflicts')
  7373.             RETURN (1)
  7374.         END
  7375.     if LOWER(@centralized_conflicts collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
  7376.         select @centralized_conflicts_id = 1
  7377.     else 
  7378.         begin
  7379.             raiserror(21349, 10, -1, @publication)
  7380.             select @backward_comp_level = 30    -- that of Sphinx SP2, in which decentrailzed logging will be supported.
  7381.             select @centralized_conflicts_id = 0
  7382.         end
  7383.  
  7384.     /*
  7385.     ** Parameter Check:  @dynamic_filter.
  7386.     */
  7387.  
  7388.     IF @dynamic_filters IS NULL OR LOWER(@dynamic_filters collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  7389.         BEGIN
  7390.             RAISERROR (14148, 16, -1, '@dynamic_filters')
  7391.             RETURN (1)
  7392.         END
  7393.  
  7394.     IF LOWER(@dynamic_filters collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
  7395.         SELECT @dynamic_filters_id = 1
  7396.     ELSE 
  7397.         SELECT @dynamic_filters_id = 0
  7398.  
  7399.     if @validate_subscriber_info is not NULL
  7400.         begin
  7401.             if @dynamic_filters_id = 0
  7402.                 begin
  7403.                     raiserror(21313, 16, -1)
  7404.                     return (1)
  7405.                 end
  7406.             exec ('select ' + @validate_subscriber_info)
  7407.             if @@ERROR<>0
  7408.                 begin
  7409.                     raiserror(21299, 16, -1, @validate_subscriber_info)
  7410.                     return (1)
  7411.                 end
  7412.         end
  7413.  
  7414.     -- Portable snapshot
  7415.     IF @snapshot_in_defaultfolder IS NULL OR LOWER(@snapshot_in_defaultfolder collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  7416.     BEGIN
  7417.         RAISERROR (14148, 16, -1, '@snapshot_in_defaultfolder')
  7418.         RETURN (1)
  7419.     END
  7420.     
  7421.     IF LOWER(@snapshot_in_defaultfolder collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  7422.     BEGIN
  7423.         SELECT @snapshot_in_defaultfolder_bit = 1
  7424.     END
  7425.     ELSE
  7426.     BEGIN
  7427.         SELECT @snapshot_in_defaultfolder_bit = 0
  7428.     END
  7429.  
  7430.     -- Pre/Post snapshot commands
  7431.     -- If @sync_method is character mode bcp, this would indicate that
  7432.     -- this publication may support non-SQL Server subscribers. In this 
  7433.     -- case, pre- and post- snapshot commands are not allowed.
  7434.     IF @sync_modeid = 1 AND 
  7435.         ((@pre_snapshot_script IS NOT NULL AND @pre_snapshot_script <> N'' ) OR
  7436.          (@post_snapshot_script IS NOT NULL AND @post_snapshot_script <> N''))
  7437.     BEGIN
  7438.         RAISERROR (21151, 16, -1)
  7439.         RETURN (1)
  7440.     END
  7441.  
  7442.     -- Parameter check - @compress_snapshot
  7443.     -- @compress_snapshot can be 1 if @alt_snapshot_folder is non-null
  7444.     IF @compress_snapshot IS NULL OR LOWER(@compress_snapshot collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  7445.     BEGIN
  7446.         RAISERROR (14148, 16, -1, '@compress_snapshot')
  7447.         RETURN (1)
  7448.     END
  7449.     
  7450.     IF LOWER(@compress_snapshot collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  7451.     BEGIN
  7452.         SELECT @compress_snapshot_bit = 1
  7453.     END
  7454.     ELSE
  7455.     BEGIN
  7456.         SELECT @compress_snapshot_bit = 0
  7457.     END
  7458.  
  7459.  
  7460.     -- Only bump up the compatibility level if only a compressed snapshot
  7461.     -- is generated at the alternate snapshot folder
  7462.     if @snapshot_in_defaultfolder_bit = 0 and
  7463.        @compress_snapshot_bit = 1
  7464.     begin
  7465.         raiserror(21350, 10, -1, @publication)
  7466.         select @backward_comp_level = 40 -- this is supported starting from 7.5
  7467.     end
  7468.  
  7469.     -- Snapshot compression can only be enabled if an alternate 
  7470.     -- snapshot generation folder exists.
  7471.     IF (@compress_snapshot_bit = 1 AND 
  7472.         (@alt_snapshot_folder IS NULL OR @alt_snapshot_folder = N''))
  7473.     BEGIN
  7474.         RAISERROR (21157, 16, -1)
  7475.         RETURN (1)
  7476.     END    
  7477.  
  7478.     -- Parameter check: ftp_address
  7479.     -- If the publication is enabled for internet, ftp_address cannot be null
  7480.     IF @enabled_for_internet_id = 1 AND (@ftp_address IS NULL OR @ftp_address = N'')
  7481.     BEGIN
  7482.         RAISERROR (21158, 16, -1)
  7483.         RETURN (1)
  7484.     END     
  7485.  
  7486.  
  7487.     -- Parameter check: enabled_for_internet
  7488.     -- If a publication is enabled for internet, it must have an alternate 
  7489.     -- snapshot folder defined.
  7490.     IF LOWER(@enabled_for_internet collate SQL_Latin1_General_CP1_CS_AS) = N'true' AND 
  7491.         (@alt_snapshot_folder = N'' OR
  7492.         (@alt_snapshot_folder IS NULL))
  7493.     BEGIN
  7494.         RAISERROR (21159, 16, -1)
  7495.         RETURN (1)
  7496.     END 
  7497.  
  7498.     -- Parameter check: ftp_port
  7499.     IF @ftp_port IS NULL
  7500.     BEGIN
  7501.         RAISERROR (21160, 16, -1)
  7502.     END
  7503.  
  7504.  
  7505.     -- Encrypt ftp password before putting it into the sysmergepublications
  7506.     -- table if one is provided
  7507.     SELECT @enc_ftp_password = NULL
  7508.     IF @ftp_password IS NOT NULL
  7509.     BEGIN
  7510.         SELECT @enc_ftp_password = @ftp_password 
  7511.         EXEC @retcode = master.dbo.xp_repl_encrypt @enc_ftp_password OUTPUT
  7512.         IF @retcode <> 0
  7513.         BEGIN
  7514.             RETURN (1)
  7515.         END
  7516.     END    
  7517.  
  7518.     /*
  7519.     ** Parameter Check:  @keep_partition_changes.
  7520.     */
  7521.  
  7522.     if LOWER(@keep_partition_changes collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  7523.         BEGIN
  7524.             RAISERROR (14148, 16, -1, '@keep_partition_changes')
  7525.             RETURN (1)
  7526.         END
  7527.  
  7528.     if LOWER(@keep_partition_changes collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
  7529.         begin
  7530.             set @keep_before_values_int = 1
  7531.         end
  7532.     else 
  7533.         set @keep_before_values_int = 0
  7534.  
  7535.     /*
  7536.     ** Parameter Check:  @allow_subscription_copy_id.
  7537.     */
  7538.  
  7539.     if LOWER(@allow_subscription_copy collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  7540.         BEGIN
  7541.             RAISERROR (14148, 16, -1, '@allow_subscription_copy')
  7542.             RETURN (1)
  7543.         END
  7544.         
  7545.     IF LOWER(@allow_subscription_copy collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
  7546.         SELECT @allow_subscription_copy_id = 1
  7547.     ELSE 
  7548.         SELECT @allow_subscription_copy_id = 0
  7549.  
  7550.     /*
  7551.     ** Parameter Check:  @allow_synctoalternate_id.
  7552.     */
  7553.  
  7554.     if LOWER(@allow_synctoalternate collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  7555.         BEGIN
  7556.             RAISERROR (14148, 16, -1, '@allow_synctoalternate')
  7557.             RETURN (1)
  7558.         END
  7559.         
  7560.     IF LOWER(@allow_synctoalternate collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
  7561.         SELECT @allow_synctoalternate_id = 1
  7562.     ELSE 
  7563.         SELECT @allow_synctoalternate_id = 0
  7564.  
  7565.     /*
  7566.     ** Parameter Check:  @add_to_active_directory.
  7567.     */
  7568.  
  7569.     if LOWER(@add_to_active_directory collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  7570.         BEGIN
  7571.             RAISERROR (14148, 16, -1, '@add_to_active_directory')
  7572.             RETURN (1)
  7573.         END
  7574.  
  7575.    /* Is AD supported? */
  7576.    DECLARE @retval  INT
  7577.    EXECUTE @retval = master.dbo.xp_MSADEnabled
  7578.    if (@retval <> 0) and LOWER(@add_to_active_directory collate SQL_Latin1_General_CP1_CS_AS)='true'
  7579.    begin
  7580.         RAISERROR(21253, 16, -1)
  7581.         RETURN (1)
  7582.    end
  7583.  
  7584.  
  7585.     /*
  7586.     ** Parameter Check: @max_concurrent_dynamic_snapshots
  7587.     */
  7588.     
  7589.     if @max_concurrent_dynamic_snapshots < 0 or @max_concurrent_dynamic_snapshots is null
  7590.     begin
  7591.         raiserror(21403, 16, -1)
  7592.         return (1)
  7593.     end
  7594.         
  7595.     /*
  7596.     ** Check to see if the publication name is already used.
  7597.     ** 1. check merge pubs
  7598.     ** 2. check online publications
  7599.     */
  7600.     if exists (select * from sysmergepublications 
  7601.         where name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name())
  7602.     begin
  7603.         RAISERROR (20025, 16, -1, @publication)
  7604.         RETURN (1)
  7605.     end
  7606.  
  7607.     if (select category & @tranpublish_bit from master..sysdatabases where name = @db_name collate database_default) <> 0
  7608.     begin
  7609.         EXEC @retcode = dbo.sp_helppublication @publication, @found output
  7610.  
  7611.         if @@ERROR <> 0 OR @retcode <> 0
  7612.         BEGIN
  7613.             RETURN (1)
  7614.         END
  7615.  
  7616.         if @found <> 0 
  7617.         BEGIN
  7618.             RAISERROR (20025, 16, -1, @publication)
  7619.             RETURN (1)
  7620.         END
  7621.     end
  7622.  
  7623.     /*
  7624.     **  Add the publication as the designmaster of the replica set.
  7625.     */
  7626.  
  7627.     /* Generate a guid for the publication ID */
  7628.     set @pubid = newid()
  7629.         
  7630.     /* Select the server's ID as 0 since this is the LOCAL server */
  7631.     select @srvid = 0
  7632.  
  7633.     /* Look for existing nickname from any other subscription */
  7634.     exec @retcode=sp_MSgetreplnick NULL, NULL , NULL,  @nickname out
  7635.     if (@@error <> 0) or @retcode <> 0 
  7636.         begin
  7637.             RETURN(1)
  7638.         end                 
  7639.             
  7640.     /* Generate a new replica nickname from the @pubid */
  7641.     if (@nickname is null)
  7642.     begin
  7643.         execute @retcode = dbo.sp_MSgenreplnickname @pubid, @nickname output
  7644.         IF @@ERROR <>0 OR @retcode <> 0
  7645.         BEGIN
  7646.             RAISERROR (20077, 16, -1)
  7647.             RETURN (1)
  7648.         END
  7649.     end
  7650.     else
  7651.         select @priority=max(priority) from sysmergesubscriptions where db_name=@db_name and srvid = @srvid
  7652.     /*
  7653.     ** A change in design.
  7654.     */
  7655.     if @priority = 0 
  7656.         begin
  7657.             RAISERROR(21087, 16, -1)
  7658.             return (1)
  7659.         end
  7660.  
  7661.     /*
  7662.     ** Get distributor information
  7663.     */
  7664.     EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUT , @distributor = @distservername  OUTPUT, 
  7665.         @distribdb = @distribdb OUTPUT
  7666.         if @@error <> 0 OR @retcode <> 0 or @distributor IS NULL OR @distribdb IS NULL
  7667.         BEGIN
  7668.             RAISERROR (14071, 16, -1)
  7669.             RETURN (1)
  7670.         END
  7671.     
  7672.     /*
  7673.     **  add an entry into sysmergepublications
  7674.     */
  7675.     begin tran    
  7676.     save tran sp_addmergepublication
  7677.         /* Add row in the publications table */
  7678.         if @backward_comp_level > 10
  7679.         begin
  7680.             exec sp_MSBumpupCompLevel @pubid, @backward_comp_level
  7681.             if @@ERROR<>0
  7682.                 goto FAILURE
  7683.         end
  7684.             
  7685.         insert sysmergepublications
  7686.             (pubid, 
  7687.             name, 
  7688.             description, 
  7689.             designmasterid, 
  7690.             retention, 
  7691.             parentid, 
  7692.             sync_mode, 
  7693.             allow_push, 
  7694.             allow_pull, 
  7695.             allow_anonymous, 
  7696.             centralized_conflicts,
  7697.             status,
  7698.             snapshot_ready,
  7699.             enabled_for_internet,
  7700.             publication_type,
  7701.             dynamic_filters,
  7702.             snapshot_in_defaultfolder,
  7703.             alt_snapshot_folder,
  7704.             pre_snapshot_script,
  7705.             post_snapshot_script,
  7706.             compress_snapshot,
  7707.             ftp_address,
  7708.             ftp_port,
  7709.             ftp_subdirectory,
  7710.             ftp_login,
  7711.             ftp_password,
  7712.             conflict_retention,
  7713.             keep_before_values,
  7714.             allow_subscription_copy,
  7715.             allow_synctoalternate,
  7716.             validate_subscriber_info,
  7717.             ad_guidname,
  7718.             backward_comp_level,
  7719.             max_concurrent_merge,
  7720.             max_concurrent_dynamic_snapshots)
  7721.         values
  7722.             (@pubid, 
  7723.             @publication, 
  7724.             @description, 
  7725.             @pubid, 
  7726.             @retention, 
  7727.             @pubid, 
  7728.             @sync_modeid, 
  7729.             @allow_push_id, 
  7730.             @allow_pull_id, 
  7731.             @allow_anonymous_id, 
  7732.             @centralized_conflicts_id,
  7733.             @statid,
  7734.             @false,
  7735.             @enabled_for_internet_id,
  7736.             @full,
  7737.             @dynamic_filters_id,
  7738.             @snapshot_in_defaultfolder_bit,
  7739.             @alt_snapshot_folder,
  7740.             @pre_snapshot_script,
  7741.             @post_snapshot_script,
  7742.             @compress_snapshot_bit,
  7743.             @ftp_address,
  7744.             @ftp_port,
  7745.             @ftp_subdirectory,
  7746.             @ftp_login,
  7747.             @enc_ftp_password,
  7748.             @conflict_retention,
  7749.             @keep_before_values_int,
  7750.             @allow_subscription_copy_id,
  7751.             @allow_synctoalternate_id,
  7752.             @validate_subscriber_info,
  7753.             @ad_guidname, 
  7754.             @backward_comp_level,
  7755.             @max_concurrent_merge,
  7756.             @max_concurrent_dynamic_snapshots)
  7757.         if @@ERROR <> 0
  7758.             begin
  7759.                 goto FAILURE
  7760.             end
  7761.  
  7762.         /* Add row to represent reciprocal subscription */
  7763.         insert sysmergesubscriptions(subid, partnerid, datasource_type, srvid, db_name, status, priority, pubid, subscriber_type, subscription_type, sync_type, login_name, subscriber_server, publication, distributor, last_validated)
  7764.             values (@pubid, @pubid, 0, @srvid, @db_name, @statid, @priority, @pubid, @global, @push, @automatic, suser_sname(suser_sid()), @@servername, @publication, @distservername, getdate())
  7765.  
  7766.         if @@ERROR <> 0
  7767.             begin
  7768.                 goto FAILURE
  7769.             end
  7770.         /*
  7771.         **  Add row for merge publication to MSmerge_replinfo.
  7772.         */
  7773.         insert MSmerge_replinfo(repid, replnickname)
  7774.             values (@pubid, @nickname)
  7775.         if @@ERROR <> 0
  7776.             begin
  7777.                 goto FAILURE
  7778.             end
  7779.  
  7780.  
  7781.         /*
  7782.         ** Add the publication to the distributor side
  7783.         */
  7784.         SELECT @distpubid = @nickname
  7785.  
  7786.         select @distproc = RTRIM(@distributor) + '.' + @distribdb + 
  7787.             '.dbo.sp_MSadd_publication'
  7788.         EXECUTE @retcode = @distproc
  7789.             @publisher = @@SERVERNAME,
  7790.             @publisher_db = @db_name,
  7791.             @publication = @publication,
  7792.             --@publication_id = NULL,
  7793.             @publication_type = 2,          -- 0 = Trans, 1 = Snapshot, 2 = Merge
  7794.             @independent_agent = @true,
  7795.             @immediate_sync = @true,
  7796.             @allow_push = @allow_push_id,
  7797.             @allow_pull = @allow_pull_id,
  7798.             @allow_anonymous = @allow_anonymous_id,
  7799.             --@snapshot_agent = NULL,
  7800.             --@logreader_agent = NULL,
  7801.             @description = @description,
  7802.             @retention = @retention,
  7803.             @allow_subscription_copy = @allow_subscription_copy_id
  7804.  
  7805.         IF @@ERROR <> 0 or @retcode <> 0
  7806.             BEGIN
  7807.                 GOTO FAILURE
  7808.             END
  7809.                 
  7810.         -- Populate the initial list.
  7811.         exec @retcode = dbo.sp_grant_publication_access 
  7812.             @publication = @publication,
  7813.             @login = null,
  7814.             @reserved = 'init'
  7815.         IF @@error <> 0 OR @retcode <> 0
  7816.             GOTO FAILURE
  7817.  
  7818.  
  7819.  
  7820.     commit tran
  7821.  
  7822.     --Put this part outside of a TRANSACTION. It can fail without having to affect publication creation.
  7823.     declare @returnstring nvarchar(512) 
  7824.     set @returnstring = N''
  7825.     if LOWER(@add_to_active_directory collate SQL_Latin1_General_CP1_CS_AS)='true'
  7826.     begin
  7827.         --no error checking needed here.    
  7828.  
  7829.         create table #guid_name_for_active_directory(ad_guidname sysname collate database_default null)
  7830.         if @@ERROR<>0
  7831.             goto SKIP_AD
  7832.         insert into #guid_name_for_active_directory exec @retcode=master.dbo.sp_ActiveDirectory_Obj 'CREATE', 'PUBLICATION', @publication, @db_name
  7833.         if @retcode <> 0 or @@ERROR<>0
  7834.         begin
  7835.             set @returnstring = (select TOP 1 ad_guidname from #guid_name_for_active_directory)
  7836.             goto SKIP_AD           
  7837.         end
  7838.         select TOP 1 @ad_guidname = ad_guidname from #guid_name_for_active_directory
  7839.         if @ad_guidname is not NULL
  7840.         begin
  7841.             update sysmergepublications set ad_guidname=@ad_guidname where pubid=@pubid
  7842.             if @@ERROR<>0
  7843.                 goto SKIP_AD
  7844.         end
  7845.         drop table #guid_name_for_active_directory
  7846.     end
  7847.     return (0)
  7848. SKIP_AD:
  7849.     drop table #guid_name_for_active_directory
  7850.     if @returnstring is NULL
  7851.         select @returnstring = N''
  7852.     raiserror(21363, 16, -1, @publication, @returnstring)
  7853.     return (1) 
  7854. FAILURE:
  7855.     RAISERROR (14018, 16, -1)
  7856.     /* UNDONE : This code is specific to 6.X nested transaction semantics */
  7857.     if @@TRANCOUNT > 0
  7858.     begin
  7859.         ROLLBACK TRANSACTION sp_addmergepublication
  7860.         COMMIT TRANSACTION
  7861.     end
  7862.     return (1)
  7863. go
  7864. exec dbo.sp_MS_marksystemobject sp_addmergepublication 
  7865. go
  7866.  
  7867. grant execute on dbo.sp_addmergepublication to public
  7868. go
  7869.  
  7870. raiserror('Creating procedure sp_changemergepublication', 0,1)
  7871. GO
  7872.  
  7873. CREATE PROCEDURE sp_changemergepublication (
  7874.     @publication sysname,                  /* Publication name */
  7875.     @property sysname = NULL,              /* The property to change */
  7876.     @value nvarchar(255) = NULL,        /* The new property value */
  7877.     @force_invalidate_snapshot bit = 0,    /* Force invalidate existing snapshot */
  7878.     @force_reinit_subscription bit = 0    /* Force reinit subscription */
  7879.     ) AS
  7880.  
  7881.     SET NOCOUNT ON
  7882.  
  7883.     /*
  7884.     ** Declarations.
  7885.     */
  7886.     declare @max_concurrent_merge    int
  7887.     declare @cmd                nvarchar(255)
  7888.     declare @pubid              uniqueidentifier
  7889.     declare @pubidstr           nvarchar(38)
  7890.     declare @retcode            int
  7891.     declare @retention          int
  7892.     declare @statusid           tinyint
  7893.     declare @sync_modeid        tinyint
  7894.     declare @distributor        sysname
  7895.     declare @distproc           nvarchar(300)
  7896.     declare @value_bit          bit
  7897.     declare @snapshot_ready     tinyint
  7898.     declare @subscribed         int
  7899.     declare @dbname             sysname
  7900.     declare @distribdb          sysname
  7901.     declare @alt_snapshot_folder nvarchar(255)
  7902.     declare @enabled_for_internet bit
  7903.     declare @ftp_address        sysname
  7904.     declare @enc_ftp_password   nvarchar(524)
  7905.     declare @snapshot_in_defaultfolder bit
  7906.     declare @dynamic_filters_id    int
  7907.     declare @schemaversion      int 
  7908.     declare @schemaguid         uniqueidentifier
  7909.     declare @schematype         int
  7910.     declare @schematext         nvarchar(2000)
  7911.     declare @artid                uniqueidentifier
  7912.     declare @in_ActiveD            bit
  7913.     declare @ad_guidname        sysname
  7914.     declare @db_name            sysname
  7915.     declare @compress_snapshot  bit
  7916.     declare @numeric_value      int
  7917.  
  7918.     /*
  7919.     ** Initializations
  7920.     */
  7921.     select @subscribed = 1
  7922.     select @snapshot_ready = 1
  7923.     select @db_name=db_name()
  7924.     /*
  7925.     ** Security Check
  7926.     */
  7927.  
  7928.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  7929.     IF @@ERROR <> 0 or @retcode <> 0
  7930.         return (1)
  7931.  
  7932.     /* 
  7933.     ** Check if current DB is enabled for publication/subscription
  7934.     */
  7935.     
  7936.     /* make sure current database is enabled for merge replication */
  7937.     exec @retcode=dbo.sp_MSCheckmergereplication
  7938.     if @@ERROR<>0 or @retcode<>0
  7939.         return (1)
  7940.             
  7941.     /*
  7942.     ** Parameter Check:  @property.
  7943.     ** If the @property parameter is NULL, print the options.
  7944.     */
  7945.     if @property IS NULL
  7946.         BEGIN
  7947.             CREATE TABLE #tab1 (properties sysname collate database_default)
  7948.             INSERT INTO #tab1 VALUES ('description')
  7949.             INSERT INTO #tab1 VALUES ('status')
  7950.             INSERT INTO #tab1 VALUES ('retention')
  7951.             INSERT INTO #tab1 VALUES ('sync_mode')
  7952.             INSERT INTO #tab1 VALUES ('allow_push')
  7953.             INSERT INTO #tab1 VALUES ('allow_pull')
  7954.             INSERT INTO #tab1 VALUES ('allow_anonymous')
  7955.             INSERT INTO #tab1 VALUES ('enabled_for_internet')
  7956.             INSERT INTO #tab1 VALUES ('centralized_conflicts')
  7957.             INSERT INTO #tab1 VALUES ('snapshot_ready')
  7958.             INSERT INTO #tab1 VALUES ('snapshot_in_defaultfolder')
  7959.             INSERT INTO #tab1 VALUES ('alt_snapshot_folder')
  7960.             INSERT INTO #tab1 VALUES ('pre_snapshot_script')
  7961.             INSERT INTO #tab1 VALUES ('post_snapshot_script')
  7962.             INSERT INTO #tab1 VALUES ('compress_snapshot')
  7963.             INSERT INTO #tab1 VALUES ('ftp_address')
  7964.             INSERT INTO #tab1 VALUES ('ftp_port')
  7965.             INSERT INTO #tab1 VALUES ('ftp_subdirectory')
  7966.             INSERT INTO #tab1 VALUES ('ftp_login')
  7967.             INSERT INTO #tab1 VALUES ('ftp_password')
  7968.             INSERT INTO #tab1 VALUES ('conflict_retention')
  7969.             INSERT INTO #tab1 VALUES ('allow_subscription_copy')
  7970.             INSERT INTO #tab1 VALUES ('allow_synctoalternate')
  7971.             INSERT INTO #tab1 VALUES ('validate_subscriber_info')
  7972.             INSERT INTO #tab1 VALUES ('publish_to_ActiveDirectory')
  7973.             INSERT INTO #tab1 VALUES ('dynamic_filters')
  7974.             INSERT INTO #tab1 VALUES ('max_concurrent_merge')
  7975.             INSERT INTO #tab1 VALUES ('max_concurrent_dynamic_snapshots')
  7976.             select * FROM #tab1
  7977.             RETURN (0)
  7978.         END
  7979.  
  7980.     if @value is NULL and LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) not in 
  7981.                                                   ('description', 
  7982.                                                    'alt_snapshot_folder',
  7983.                                                    'pre_snapshot_script',
  7984.                                                    'post_snapshot_script',
  7985.                                                    'ftp_address',
  7986.                                                    'ftp_subdirectory',
  7987.                                                    'ftp_login',
  7988.                                                    'ftp_password',
  7989.                                                    'max_concurrent_merge')
  7990.         begin
  7991.             RAISERROR (20081, 16, -1, @property)
  7992.             RETURN (1)
  7993.         end
  7994.  
  7995.     /*
  7996.     ** Parameter Check:  @publication.
  7997.     ** Make sure that the publication exists.
  7998.     */
  7999.  
  8000.     if @publication IS NULL
  8001.         BEGIN
  8002.             RAISERROR (14043, 16, -1, '@publication')
  8003.             RETURN (1)
  8004.         END
  8005.  
  8006.     select @pubid = pubid, 
  8007.            @ad_guidname=ad_guidname, --with value NULL if this publication is not in AD.
  8008.            @snapshot_ready=snapshot_ready,
  8009.            @dynamic_filters_id=dynamic_filters,
  8010.            @sync_modeid = sync_mode, 
  8011.            @alt_snapshot_folder = alt_snapshot_folder,
  8012.            @enabled_for_internet = enabled_for_internet,
  8013.            @ftp_address = ftp_address,
  8014.            @snapshot_in_defaultfolder = snapshot_in_defaultfolder,
  8015.            @compress_snapshot = compress_snapshot,
  8016.            @in_ActiveD = case when ad_guidname is NULL then 0 else 1 end 
  8017.       FROM sysmergepublications 
  8018.      WHERE name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  8019.     set @pubidstr = '''' + convert(nchar(36), @pubid) + ''''
  8020.  
  8021.     if @pubid IS NULL
  8022.         BEGIN
  8023.             RAISERROR (20026, 16, -1, @publication)
  8024.             RETURN (1)
  8025.         END
  8026.     else
  8027.  
  8028.     /*
  8029.     ** Parameter Check:  @property.
  8030.     ** Check to make sure that @property is a valid property in
  8031.     ** sysmergepublications.
  8032.     */
  8033.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('description', 'status', 'retention', 'sync_mode', 'allow_push', 
  8034.         'allow_pull', 'allow_anonymous', 'enabled_for_internet', 'centralized_conflicts', 'snapshot_ready', 
  8035.         'snapshot_in_defaultfolder', 'alt_snapshot_folder', 'pre_snapshot_script', 'post_snapshot_script', 
  8036.         'compress_snapshot', 'ftp_address', 'ftp_port', 'ftp_subdirectory','ftp_login',
  8037.         'ftp_password', 'conflict_retention', 'allow_subscription_copy', 'allow_synctoalternate',
  8038.         'validate_subscriber_info','publish_to_activedirectory','dynamic_filters','max_concurrent_merge', 'max_concurrent_dynamic_snapshots') 
  8039.         BEGIN
  8040.             RAISERROR (21053, 16, -1)
  8041.             RETURN (1)
  8042.         END
  8043.  
  8044.  
  8045.     /*
  8046.     ** Parameter Check:
  8047.     ** If sync_method of the publication is character mode (an indication that it supports
  8048.     ** third party Subscribers), pre/post-snapshot setting must be null   
  8049.     **
  8050.     */
  8051.     IF @sync_modeid = 1 
  8052.     BEGIN
  8053.         IF (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'pre_snapshot_script' OR
  8054.             LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'post_snapshot_script') AND
  8055.             @value IS NOT NULL AND @value <> ''
  8056.         BEGIN
  8057.             RAISERROR (21151, 16, -1)
  8058.             RETURN (1)
  8059.         END   
  8060.     END
  8061.  
  8062.     /*
  8063.     ** Parameter Check:
  8064.     ** If the Publication's alt_snapshot_folder setting is null 
  8065.     ** snapshot compression cannot be enabled
  8066.     */
  8067.     IF ((@alt_snapshot_folder IS NULL OR @alt_snapshot_folder = '')) 
  8068.         AND LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'compress_snapshot'
  8069.         AND LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'   
  8070.     BEGIN
  8071.         RAISERROR (21157, 16, -1)        
  8072.         RETURN (1)
  8073.     END
  8074.  
  8075.     /* 
  8076.     ** Parameter Check:
  8077.     ** If enabled_for_internet is set to true, the publication must have a non-null
  8078.     ** ftp_address.
  8079.     */
  8080.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'enabled_for_internet' AND
  8081.        LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'true' AND 
  8082.        (@ftp_address IS NULL OR @ftp_address = N'')
  8083.     BEGIN
  8084.         RAISERROR(21158, 16, -1)
  8085.         RETURN (1)
  8086.     END
  8087.  
  8088.     /*
  8089.     ** .. and ftp_address cannot be null if the publication is enabled for 
  8090.     ** internet.
  8091.     */
  8092. /*
  8093.     IF @enabled_for_internet = 1 AND
  8094.       (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_address'
  8095.         AND (@value IS NULL OR @value = N''))
  8096.     BEGIN
  8097.         RAISERROR(21158, 16, -1)
  8098.         RETURN (1)
  8099.     END
  8100. */
  8101.     /*
  8102.     ** .. and 'alternate snapshot folder' is not null and
  8103.     ** 'snapshot in default folder' is false
  8104.     **
  8105.     */
  8106.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'enabled_for_internet' AND
  8107.         LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'true' AND
  8108.        (@alt_snapshot_folder IS NULL OR @alt_snapshot_folder = N'')
  8109.     BEGIN
  8110.         RAISERROR(21159, 16, -1)
  8111.         RETURN (1)
  8112.     END 
  8113.  
  8114. /*
  8115.     IF @enabled_for_internet = 1 AND
  8116.        (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'alt_snapshot_folder' AND
  8117.         (LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IS NULL OR LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N''))
  8118.     BEGIN
  8119.         RAISERROR(21159, 16, -1)
  8120.         RETURN (1)
  8121.     END  
  8122. */
  8123.  
  8124.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='validate_subscriber_info'
  8125.     begin
  8126.         if exists (select * from sysmergesubscriptions where pubid=@pubid and subid<>@pubid and status<>0)
  8127.             begin
  8128.                 raiserror(21501, 16, -1)
  8129.                 return (1)
  8130.             end    
  8131.     end
  8132.  
  8133.     /*
  8134.     ** Parameter Check:
  8135.     ** 'ftp_port' cannot be null
  8136.     */
  8137.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_port' AND @value IS NULL
  8138.     BEGIN
  8139.         RAISERROR (14043, 16, -1, @property)
  8140.         RETURN (1)
  8141.     END
  8142.  
  8143.     BEGIN TRAN changemergepublication    
  8144.     save tran changemergepublication
  8145.  
  8146.     /*
  8147.     ** Changing of the following properties would require a snapshot rerun, if snapshot is ready
  8148.     */
  8149.     if (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) like 'ftp%' OR LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ('sync_mode', 'snapshot_in_defaultfolder',
  8150.             'alt_snapshot_folder', 'pre_snapshot_script', 'post_snapshot_script','compress_snapshot'))
  8151.     and @snapshot_ready>0
  8152.     begin
  8153.         if @force_invalidate_snapshot = 0
  8154.         begin
  8155.             raiserror(20607, 16, -1)
  8156.             goto UNDO
  8157.         end
  8158.         update sysmergepublications set snapshot_ready=2 where pubid=@pubid and snapshot_ready=1
  8159.         if @@ERROR<>0    GOTO UNDO
  8160.     end
  8161.  
  8162.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='dynamic_filters'
  8163.     begin
  8164.         if @snapshot_ready>0
  8165.         begin
  8166.             if @force_invalidate_snapshot = 0
  8167.             begin
  8168.                 raiserror(20607, 16, -1)
  8169.                 goto UNDO
  8170.             end
  8171.             if @force_reinit_subscription = 0
  8172.             begin
  8173.                 raiserror(20608, 16, -1)
  8174.                 goto UNDO
  8175.             end
  8176.             update sysmergepublications set snapshot_ready=2 where pubid=@pubid
  8177.         end
  8178.  
  8179.         if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
  8180.             select @dynamic_filters_id = 1
  8181.         else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'false' 
  8182.                select @dynamic_filters_id = 0
  8183.            else
  8184.                begin
  8185.                    raiserror(14137, 16, -1)
  8186.                    goto UNDO
  8187.                end
  8188.  
  8189.         update sysmergepublications set dynamic_filters=@dynamic_filters_id where pubid=@pubid
  8190.         if @@ERROR<>0
  8191.             goto UNDO
  8192.         exec @retcode = sp_MSreinitmergepublication @publication
  8193.         if @retcode<>0 or @@ERROR<>0
  8194.             goto UNDO
  8195.     end
  8196.     
  8197.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='validate_subscriber_info'
  8198.     begin
  8199.         if @value is not NULL
  8200.         begin
  8201.             if @dynamic_filters_id = 0
  8202.                 begin
  8203.                     raiserror(21313, 16, -1)
  8204.                     GOTO UNDO
  8205.                 end
  8206.             exec ('select ' + @value)
  8207.             if @@ERROR<>0
  8208.                 begin
  8209.                     raiserror(21299, 16, -1, @value)
  8210.                     GOTO UNDO
  8211.                 end
  8212.         end
  8213.  
  8214.         UPDATE sysmergepublications  SET validate_subscriber_info = @value WHERE pubid = @pubid
  8215.         if @@ERROR <> 0 GOTO UNDO
  8216.     end
  8217.  
  8218.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('description')
  8219.         BEGIN
  8220.             UPDATE sysmergepublications  SET description = @value WHERE pubid = @pubid
  8221.             if @@ERROR <> 0 GOTO UNDO
  8222.         END
  8223.  
  8224.   
  8225.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'status'
  8226.         BEGIN
  8227.  
  8228.             /*
  8229.             ** Check to make sure that we have a valid status.
  8230.             */
  8231.  
  8232.             if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('active', 'inactive')
  8233.                 BEGIN
  8234.                     RAISERROR (14012, 16, -1)
  8235.                     GOTO UNDO
  8236.                 END
  8237.  
  8238.             /*
  8239.             ** Determine the integer value for the status.
  8240.             */
  8241.  
  8242.             if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'active'
  8243.                 select @statusid = 1
  8244.             else
  8245.                 select @statusid = 0
  8246.  
  8247.             /*
  8248.             ** Update the publication with the new status.
  8249.             */
  8250.  
  8251.             UPDATE sysmergepublications SET status = @statusid WHERE pubid = @pubid
  8252.  
  8253.             if @@ERROR <> 0 GOTO UNDO
  8254.         END
  8255.  
  8256.  
  8257.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'retention'
  8258.         BEGIN
  8259.         /*
  8260.         ** Update the publication with the new replication frequency.
  8261.         */
  8262.  
  8263.         select @retention = CONVERT(int, @value)
  8264.         if @@error <>0 goto UNDO
  8265.  
  8266.         if @retention is NULL 
  8267.             select @retention = 0
  8268.  
  8269.            if @retention < 0
  8270.                begin
  8271.                    raiserror(20050, 16, -1, 0)
  8272.                    GOTO UNDO
  8273.                end
  8274.  
  8275.         UPDATE sysmergepublications set retention = @retention WHERE pubid = @pubid
  8276.         if @@ERROR <> 0 
  8277.             GOTO UNDO
  8278.  
  8279.         select @schemaversion = schemaversion from sysmergeschemachange
  8280.         if (@schemaversion is NULL)
  8281.             set @schemaversion = 1
  8282.         else
  8283.             select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
  8284.             
  8285.         set @schemaguid = newid()
  8286.         set @artid = newid()
  8287.         set @schematype = 9 /* change retention */
  8288.         select @schematext = 'exec dbo.sp_MSchange_retention '+ '''' + convert(nchar(36),@pubid) + '''' + ',' + '''' + @value + ''''          
  8289.         exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
  8290.             if @@ERROR<>0 or @retcode<>0 goto UNDO    
  8291.  
  8292.  
  8293.         END
  8294.  
  8295.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'conflict_retention'
  8296.         BEGIN
  8297.         /*
  8298.         ** Update the publication with the new conflict_retention value
  8299.         */
  8300.  
  8301.         select @retention = CONVERT(int, @value)
  8302.         if @@ERROR<>0
  8303.             GOTO UNDO
  8304.  
  8305.         if @value is NULL 
  8306.             select @retention = 0
  8307.  
  8308.            if @retention < 0
  8309.                begin
  8310.                    raiserror(20050, 16, -1, 0)
  8311.                    GOTO UNDO
  8312.                end
  8313.  
  8314.         UPDATE sysmergepublications
  8315.             SET conflict_retention = @retention
  8316.             WHERE pubid = @pubid
  8317.  
  8318.         if @@ERROR <> 0 
  8319.             GOTO UNDO
  8320.  
  8321.         END
  8322.  
  8323.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'max_concurrent_merge'
  8324.         BEGIN
  8325.         /*
  8326.         ** Update the publication property <max_concurrent_merge> with a new value
  8327.         */
  8328.  
  8329.         select @max_concurrent_merge = CONVERT(int, @value)
  8330.         if @max_concurrent_merge < 0    
  8331.         begin
  8332.             raiserror(21402, 16, -1, '@value')
  8333.             GOTO UNDO
  8334.         end
  8335.  
  8336.         UPDATE sysmergepublications
  8337.             SET max_concurrent_merge = @max_concurrent_merge
  8338.             WHERE pubid = @pubid
  8339.  
  8340.         if @@ERROR <> 0 
  8341.             GOTO UNDO
  8342.  
  8343.         END
  8344.  
  8345.  
  8346.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'sync_mode'
  8347.         BEGIN
  8348.  
  8349.             /*
  8350.             ** Check for a valid synchronization method.
  8351.             */
  8352.             if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS)='portable' select @value='character'
  8353.  
  8354.             if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('native', 'character', 'bcp native', 'bcp character')
  8355.                 begin
  8356.                 raiserror (20076, 16, -1)
  8357.                 GOTO UNDO
  8358.                 end
  8359.  
  8360.             /*
  8361.             ** Determine the integer value for the sync_mode.
  8362.             */
  8363.             if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IN ('native', 'bcp native')
  8364.                 select @sync_modeid = 0
  8365.             else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IN ('character', 'bcp character')
  8366.                 select @sync_modeid = 1
  8367.  
  8368.             /*
  8369.             ** Update the publication with the new synchronization method.
  8370.             */
  8371.  
  8372.             UPDATE sysmergepublications
  8373.                SET sync_mode = @sync_modeid
  8374.              WHERE pubid = @pubid
  8375.  
  8376.             if @@ERROR <> 0 GOTO UNDO
  8377.         END
  8378.  
  8379.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'alt_snapshot_folder'
  8380.         BEGIN
  8381.             -- If the alt_snapshot_folder is set to '' or NULL,
  8382.             -- set the compress_snapshot bit to 0 and disable internet 
  8383.             -- support
  8384.   
  8385.             IF @value IS NULL OR @value = N''
  8386.             BEGIN
  8387.                 UPDATE sysmergepublications
  8388.                    SET alt_snapshot_folder = @value,
  8389.                        compress_snapshot = 0,
  8390.                        enabled_for_internet = 0
  8391.                  WHERE pubid = @pubid
  8392.             END
  8393.             ELSE
  8394.             BEGIN
  8395.                 UPDATE sysmergepublications
  8396.                    SET alt_snapshot_folder = @value
  8397.                  WHERE pubid = @pubid
  8398.             END
  8399.             IF @@error <> 0
  8400.             BEGIN
  8401.                GOTO UNDO
  8402.             END
  8403.         END
  8404.  
  8405.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'pre_snapshot_script'
  8406.         BEGIN
  8407.             UPDATE sysmergepublications
  8408.                SET pre_snapshot_script = @value
  8409.              WHERE pubid = @pubid
  8410.             IF @@error <> 0
  8411.             BEGIN
  8412.                GOTO UNDO
  8413.             END
  8414.         END
  8415.  
  8416.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'post_snapshot_script'
  8417.         BEGIN
  8418.             UPDATE sysmergepublications
  8419.                SET post_snapshot_script = @value
  8420.              WHERE pubid = @pubid
  8421.             IF @@error <> 0
  8422.             BEGIN
  8423.                GOTO UNDO
  8424.             END
  8425.         END
  8426.  
  8427.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_address'
  8428.         BEGIN
  8429.             IF @value IS NULL OR @value = N''    
  8430.             BEGIN
  8431.                 UPDATE sysmergepublications
  8432.                    SET ftp_address = @value,
  8433.                        enabled_for_internet = 0
  8434.                  WHERE pubid = @pubid
  8435.                 IF @@error <> 0
  8436.                 BEGIN
  8437.                     GOTO UNDO
  8438.                 END
  8439.             END
  8440.             ELSE
  8441.             BEGIN
  8442.                 UPDATE sysmergepublications
  8443.                    SET ftp_address = @value
  8444.                  WHERE pubid = @pubid
  8445.                 IF @@error <> 0
  8446.                 BEGIN
  8447.                     GOTO UNDO
  8448.                 END
  8449.             END
  8450.         END
  8451.             
  8452.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_port'
  8453.         BEGIN
  8454.             UPDATE sysmergepublications
  8455.                SET ftp_port = CONVERT(int, @value)
  8456.              WHERE pubid = @pubid
  8457.             IF @@error <> 0
  8458.             BEGIN
  8459.                GOTO UNDO
  8460.             END
  8461.         END
  8462.  
  8463.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_subdirectory'
  8464.         BEGIN
  8465.             UPDATE sysmergepublications
  8466.                SET ftp_subdirectory = @value
  8467.              WHERE pubid = @pubid
  8468.             IF @@error <> 0
  8469.             BEGIN
  8470.                GOTO UNDO
  8471.             END
  8472.         END
  8473.  
  8474.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_login'
  8475.         BEGIN
  8476.             UPDATE sysmergepublications
  8477.                SET ftp_login = @value
  8478.              WHERE pubid = @pubid
  8479.             IF @@error <> 0
  8480.             BEGIN
  8481.                GOTO UNDO
  8482.             END
  8483.         END
  8484.  
  8485.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_password'
  8486.         BEGIN
  8487.             SELECT @enc_ftp_password = NULL
  8488.             IF @value IS NOT NULL
  8489.             BEGIN
  8490.                 SELECT @enc_ftp_password = @value
  8491.                 EXEC @retcode = master.dbo.xp_repl_encrypt @enc_ftp_password OUTPUT
  8492.                 IF @retcode <> 0
  8493.                 BEGIN
  8494.                     GOTO UNDO
  8495.                 END
  8496.             END
  8497.  
  8498.             UPDATE sysmergepublications
  8499.                SET ftp_password = @enc_ftp_password
  8500.              WHERE pubid = @pubid
  8501.             IF @@error <> 0
  8502.             BEGIN
  8503.                GOTO UNDO
  8504.             END
  8505.         END
  8506.  
  8507.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'max_concurrent_dynamic_snapshots'
  8508.         BEGIN
  8509.             SELECT @numeric_value = CONVERT(int, @value)
  8510.             IF @@ERROR<>0 OR @numeric_value < 0 OR @numeric_value IS NULL
  8511.             BEGIN
  8512.                 RAISERROR(21403, 16, -1)
  8513.                 GOTO UNDO
  8514.             END
  8515.  
  8516.             UPDATE sysmergepublications
  8517.                SET max_concurrent_dynamic_snapshots = @numeric_value
  8518.              WHERE pubid = @pubid
  8519.             IF @@error <> 0
  8520.             BEGIN 
  8521.                 GOTO UNDO
  8522.             END 
  8523.         END            
  8524.  
  8525.    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'publish_to_activedirectory'
  8526.    BEGIN
  8527.         if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  8528.         BEGIN
  8529.             RAISERROR (14137, 16, -1)
  8530.             GOTO UNDO
  8531.         END
  8532.  
  8533.         /* Is AD supported? */
  8534.         DECLARE @retval  INT
  8535.         EXECUTE @retval = master.dbo.xp_MSADEnabled
  8536.         if (@retval <> 0)
  8537.         begin
  8538.             RAISERROR(21254, 16, -1, @publication)
  8539.             RETURN (1)
  8540.         end
  8541.  
  8542.            if @in_ActiveD=0 and LOWER(@value collate SQL_Latin1_General_CP1_CS_AS)='true'
  8543.            BEGIN
  8544.             create table #guid_name_for_active_directory(ad_guidname sysname collate database_default null)
  8545.             if @@ERROR<>0
  8546.             begin
  8547.                 raiserror(21363, 16, -1, @publication, N'')
  8548.                 goto UNDO            
  8549.             end
  8550.             insert into #guid_name_for_active_directory exec @retcode=master.dbo.sp_ActiveDirectory_Obj 'CREATE', 'PUBLICATION', @publication, @db_name
  8551.             if @retcode <> 0 or @@ERROR<>0
  8552.             begin
  8553.                 declare @errorstring nvarchar(512)
  8554.                 select @errorstring = (select TOP 1 ad_guidname from #guid_name_for_active_directory) 
  8555.                 drop table #guid_name_for_active_directory
  8556.                 if @errorstring is NULL
  8557.                     select @errorstring=N''
  8558.                 raiserror(21363, 16, -1, @publication, @errorstring)
  8559.                 GOTO UNDO
  8560.                end
  8561.             select TOP 1 @ad_guidname = ad_guidname from #guid_name_for_active_directory
  8562.             if @ad_guidname is not NULL
  8563.             begin
  8564.                 update sysmergepublications set ad_guidname=@ad_guidname where pubid=@pubid
  8565.                 if @@ERROR<>0
  8566.                 begin
  8567.                     drop table #guid_name_for_active_directory
  8568.                     raiserror(21363, 16, -1, @publication, N'')
  8569.                     goto UNDO
  8570.                 end
  8571.             end
  8572.             drop table #guid_name_for_active_directory
  8573.            END
  8574.            else if @in_ActiveD=1 and LOWER(@value collate SQL_Latin1_General_CP1_CS_AS)='false'
  8575.            BEGIN
  8576.             exec @retcode=master.dbo.sp_ActiveDirectory_Obj 'DELETE', 'PUBLICATION', @publication, @db_name, @ad_guidname
  8577.             if @@ERROR<>0 or @retcode<>0
  8578.             begin
  8579.                 raiserror(21369, 16, -1, @publication)    
  8580.                 goto UNDO
  8581.             end
  8582.             update sysmergepublications set ad_guidname=NULL where pubid=@pubid
  8583.             if @@ERROR<>0
  8584.             begin
  8585.                 raiserror(21369, 16, -1, @publication)    
  8586.                 goto UNDO
  8587.             end
  8588.            END
  8589.    END
  8590.  
  8591.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('allow_push', 'allow_pull', 'allow_anonymous', 'enabled_for_internet',
  8592.         'centralized_conflicts', 'snapshot_ready', 'snapshot_in_defaultfolder', 'compress_snapshot', 
  8593.         'allow_subscription_copy', 'allow_synctoalternate')
  8594.     BEGIN
  8595.  
  8596.         /*
  8597.         ** Check for a valid  value.
  8598.         */
  8599.  
  8600.         if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  8601.         BEGIN
  8602.             RAISERROR (14137, 16, -1)
  8603.             GOTO UNDO
  8604.         END
  8605.  
  8606.         /*
  8607.         ** set value bit
  8608.         */
  8609.         if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  8610.             select @value_bit = 1
  8611.         else 
  8612.             select @value_bit = 0
  8613.  
  8614.  
  8615.         if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_anonymous'
  8616.         BEGIN
  8617.             /* Update the allow_anonymous column */
  8618.             UPDATE sysmergepublications 
  8619.                 SET allow_anonymous = @value_bit
  8620.                 WHERE pubid = @pubid
  8621.             if @@error <> 0
  8622.             BEGIN
  8623.                GOTO UNDO
  8624.             END
  8625.  
  8626.         END
  8627.  
  8628.         if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_push'
  8629.         BEGIN
  8630.             /* Update the allow_push column */
  8631.             UPDATE sysmergepublications 
  8632.                 SET allow_push = @value_bit
  8633.                 WHERE pubid = @pubid
  8634.             if @@error <> 0
  8635.             BEGIN
  8636.                GOTO UNDO
  8637.             END
  8638.         END
  8639.  
  8640.         if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_pull'
  8641.         BEGIN
  8642.  
  8643.             /* Update the allow_pull column */
  8644.             UPDATE sysmergepublications 
  8645.                 SET allow_pull = @value_bit
  8646.                 WHERE pubid = @pubid
  8647.             if @@error <> 0
  8648.             BEGIN
  8649.                GOTO UNDO
  8650.             END
  8651.         END
  8652.  
  8653.         if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'centralized_conflicts'
  8654.         BEGIN
  8655.             /* Update the centralized_conflicts column */
  8656.             UPDATE sysmergepublications 
  8657.                 SET centralized_conflicts = @value_bit
  8658.                 WHERE pubid = @pubid
  8659.             if @@error <> 0
  8660.             BEGIN
  8661.                GOTO UNDO
  8662.             END
  8663.  
  8664.             if @value_bit=0 and @snapshot_ready>0
  8665.             begin            
  8666.             -- changing to decentralized conflict logging will require reinitialization but no snapshot rerun
  8667.                 if @force_reinit_subscription = 0
  8668.                 begin
  8669.                     raiserror(20608, 16, -1)
  8670.                     goto UNDO
  8671.                 end
  8672.                 exec @retcode = sp_MSreinitmergepublication @publication
  8673.                 if @@ERROR<>0 or @retcode<>0
  8674.                     goto UNDO
  8675.             end
  8676.         END
  8677.  
  8678.         if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'enabled_for_internet'
  8679.         BEGIN
  8680.             UPDATE sysmergepublications 
  8681.                SET enabled_for_internet = @value_bit
  8682.              WHERE pubid = @pubid
  8683.  
  8684.             IF @@error <> 0
  8685.             BEGIN
  8686.                GOTO UNDO
  8687.             END
  8688.         END
  8689.  
  8690.         if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'snapshot_ready'
  8691.         BEGIN
  8692.             /* Update the allow_anonymous column */
  8693.             UPDATE sysmergepublications 
  8694.                 SET snapshot_ready = @value_bit
  8695.                 WHERE pubid = @pubid
  8696.             if @@error <> 0
  8697.             BEGIN
  8698.                GOTO UNDO
  8699.             END
  8700.  
  8701.         END
  8702.  
  8703.         IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'snapshot_in_defaultfolder'
  8704.         BEGIN
  8705.             -- snapshot_in_defaultfolder = 1 is only meaningful when
  8706.             -- alt_snapshot_folder is non-null, otherwise 
  8707.             -- a copy of the snapshot files is always kept
  8708.             -- at the publisher's working directory 
  8709.     
  8710.             UPDATE sysmergepublications 
  8711.                SET snapshot_in_defaultfolder = @value_bit
  8712.              WHERE pubid = @pubid
  8713.             IF @@error <> 0
  8714.             BEGIN
  8715.                 GOTO UNDO
  8716.             END                
  8717.  
  8718.             -- Bump up the compatibility level if we are
  8719.             -- setting snapshot_in_defaultfolder to 0
  8720.             -- and compression is enabled. i.e. only 
  8721.             -- a compressed snapshot will be generated
  8722.             -- Note that alt_snapshot_folder is implicitly
  8723.             -- specified for the publication
  8724.             IF @value_bit = 0 and @compress_snapshot = 1 
  8725.             BEGIN
  8726.                 EXEC @retcode = sp_MSBumpupCompLevel @pubid, 40
  8727.                 IF @@ERROR<>0 OR @retcode<>0
  8728.                     GOTO UNDO
  8729.             END
  8730.  
  8731.         END
  8732.         
  8733.         IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'compress_snapshot'
  8734.         BEGIN
  8735.  
  8736.             UPDATE sysmergepublications
  8737.                SET compress_snapshot = @value_bit
  8738.              WHERE pubid = @pubid
  8739.             IF @@error <> 0
  8740.             BEGIN
  8741.                 GOTO UNDO
  8742.             END
  8743.  
  8744.             -- See comment for 'snapshot_in_defaultfolder'
  8745.             IF @value_bit = 1 and @snapshot_in_defaultfolder = 0
  8746.             BEGIN
  8747.                 EXEC @retcode = sp_MSBumpupCompLevel @pubid, 40
  8748.                 IF @@ERROR<>0 OR @retcode<>0
  8749.                     GOTO UNDO
  8750.             END
  8751.         END
  8752.  
  8753.         if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_subscription_copy'
  8754.         BEGIN
  8755.             /* Update the allow_subscription_copy column */
  8756.             UPDATE sysmergepublications 
  8757.                 SET allow_subscription_copy = @value_bit
  8758.                 WHERE pubid = @pubid
  8759.             if @@error <> 0
  8760.             BEGIN
  8761.                GOTO UNDO
  8762.             END
  8763.         END
  8764.         if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_synctoalternate'
  8765.         BEGIN
  8766.             /* Update the allow_synctoalternate column */
  8767.             UPDATE sysmergepublications 
  8768.                 SET allow_synctoalternate = @value_bit
  8769.                 WHERE pubid = @pubid
  8770.             if @@error <> 0
  8771.             BEGIN
  8772.                GOTO UNDO
  8773.             END
  8774.         END
  8775.     END
  8776.  
  8777.     /*
  8778.     ** Update merge publication property at distributor side if necessaray 
  8779.     */
  8780.     
  8781.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('description','allow_push', 'allow_pull', 'allow_anonymous','retention', 'allow_subscription_copy')
  8782.     BEGIN
  8783.  
  8784.         IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('allow_push', 'allow_pull', 'allow_anonymous','allow_subscription_copy')
  8785.             
  8786.         /* Translate values */
  8787.         BEGIN            
  8788.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  8789.                 SELECT @value = '1'
  8790.             ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'false'
  8791.                     SELECT @value = '0'
  8792.         END
  8793.         /*
  8794.         ** Get distribution server information for remote RPC call.
  8795.         */
  8796.         EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
  8797.            @distribdb   = @distribdb OUTPUT
  8798.         IF @@ERROR <> 0 or @retcode <> 0
  8799.             BEGIN
  8800.                 GOTO UNDO
  8801.             END
  8802.  
  8803.         SELECT @dbname =  DB_NAME()
  8804.         
  8805.         SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + 
  8806.             '.dbo.sp_MSchange_publication'
  8807.     
  8808.         EXECUTE @retcode = @distproc
  8809.             @publisher = @@SERVERNAME,
  8810.             @publisher_db = @dbname,
  8811.             @publication = @publication,
  8812.             @property = @property,
  8813.             @value = @value
  8814.  
  8815.         IF @@ERROR <> 0 OR @retcode <> 0
  8816.         BEGIN
  8817.             GOTO UNDO
  8818.         END
  8819.     END
  8820.  
  8821.     COMMIT TRAN
  8822.  
  8823.     --update its registration in active directory
  8824.     if @in_ActiveD=1 and LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('description','allow_pull', 'allow_anonymous')
  8825.     begin
  8826.         create table #guid_name_for_ADupdate(ad_guidname sysname collate database_default null)
  8827.         if @@ERROR<>0
  8828.         begin
  8829.             goto FAILURE
  8830.         end
  8831.         insert into #guid_name_for_ADupdate exec @retcode = master.dbo.sp_ActiveDirectory_Obj N'UPDATE', N'PUBLICATION', @publication, @db_name, @ad_guidname
  8832.         if @@ERROR<>0 or @retcode<>0
  8833.         begin
  8834.             goto FAILURE                     
  8835.            end
  8836.         select TOP 1 @ad_guidname = ad_guidname from #guid_name_for_ADupdate
  8837.         if @ad_guidname is not NULL
  8838.         begin
  8839.             update sysmergepublications set ad_guidname=@ad_guidname where pubid=@pubid
  8840.             if @@ERROR<>0
  8841.                 goto FAILURE                     
  8842.         end
  8843.         drop table #guid_name_for_ADupdate
  8844.     end
  8845.  
  8846.     /*
  8847.     ** Return succeed.
  8848.     */
  8849.     
  8850.     RAISERROR (14077, 10, -1)
  8851.     RETURN (0)
  8852. FAILURE:
  8853.     drop table #guid_name_for_ADupdate
  8854.     raiserror(21371, 10, -1, @publication)
  8855.     return (1)   
  8856.  
  8857. UNDO: 
  8858.     if @@TRANCOUNT > 0
  8859.     begin
  8860.         ROLLBACK TRANSACTION changemergepublication
  8861.         COMMIT TRANSACTION
  8862.     end
  8863. GO
  8864. exec dbo.sp_MS_marksystemobject sp_changemergepublication 
  8865. go
  8866.  
  8867. grant execute on dbo.sp_changemergepublication to public
  8868. go
  8869.  
  8870. raiserror('Creating procedure sp_helpmergepublication', 0,1)
  8871. GO
  8872.  
  8873. CREATE PROCEDURE sp_helpmergepublication (
  8874.     @publication    sysname = '%',    /* The publication name */
  8875.     @found          int         = NULL  OUTPUT,
  8876.     @publication_id uniqueidentifier = NULL OUTPUT,
  8877.     @reserved       nvarchar(20) = NULL
  8878.     ) AS
  8879.  
  8880.     SET NOCOUNT ON
  8881.  
  8882.     /*
  8883.     ** Declarations.
  8884.     */
  8885.  
  8886.     declare @retcode            int
  8887.     declare @no_row             bit
  8888.     declare @our_srvid          int
  8889.     declare @has_subscription   bit
  8890.  
  8891.     /*
  8892.     ** Initializations.
  8893.     */
  8894.     select @has_subscription = 0
  8895.  
  8896.     if @found is NULL 
  8897.     BEGIN
  8898.         select @no_row=0
  8899.     END
  8900.     else
  8901.     BEGIN
  8902.         select @no_row=1
  8903.     END
  8904.     select @found       = 0
  8905.     select @our_srvid = max(srvid) from master.dbo.sysservers where UPPER(srvname) = UPPER(@@SERVERNAME) collate database_default
  8906.  
  8907.     
  8908.     /*
  8909.     ** Running sp_help is OK from everywhere, whether enabled for publishing or not
  8910.     */
  8911.     
  8912.     IF not exists (select * from sysobjects where name='sysmergesubscriptions')
  8913.         RETURN (0)
  8914.  
  8915.  
  8916.     /*
  8917.     ** Parameter Check:  @publication.
  8918.     ** Check to make sure that there are some publications
  8919.     ** to display.
  8920.     */
  8921.  
  8922.     if @publication IS NULL
  8923.         BEGIN
  8924.             RAISERROR (14043, 16, -1, '@publication')
  8925.             RETURN (1)
  8926.         END
  8927.  
  8928.     if @publication <> '%'
  8929.     begin
  8930.         -- do a pal role check
  8931.         declare @pubid uniqueidentifier
  8932.         select @pubid = pubid from dbo.sysmergepublications 
  8933.             where UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() and name = @publication
  8934.         if @pubid is not NULL
  8935.         begin
  8936.             if {fn ISPALUSER(@pubid)} <> 1
  8937.             begin
  8938.                 declare @pubidstr nvarchar(36)
  8939.                 declare @role sysname
  8940.                 
  8941.                 exec dbo.sp_MSguidtostr @pubid, @pubidstr output
  8942.                 set @role = 'MSmerge_' + @pubidstr
  8943.                 if not exists (select * from dbo.sysusers where issqlrole=1 and name=@role)
  8944.                 begin
  8945.                     RAISERROR (21423, 16, -1, @publication)
  8946.                     return 1
  8947.                 end
  8948.             end
  8949.         end
  8950.     end
  8951.     IF LOWER(@reserved collate SQL_Latin1_General_CP1_CS_AS) = 'internal'
  8952.         GOTO SelectPubs
  8953.     
  8954.     if  NOT EXISTS (select * FROM sysmergepublications pub, sysmergesubscriptions sub
  8955.         WHERE pub.name like @publication  
  8956.             and UPPER(pub.publisher)=UPPER(@@servername) 
  8957.             and pub.publisher_db=db_name() 
  8958.             and sub.pubid = pub.pubid  
  8959.             and sub.srvid = @our_srvid 
  8960.             and sub.db_name = db_name())
  8961.         BEGIN
  8962.             select @found = 0
  8963.             RETURN (0) 
  8964.         END
  8965.     else
  8966.         BEGIN
  8967.             select @found = 1
  8968.             select @publication_id = pubid FROM sysmergepublications 
  8969.                 WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  8970.             if exists (select * from sysmergesubscriptions where pubid<>subid and pubid in 
  8971.                 (select pubid from sysmergepublications where name like @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()))
  8972.                 select @has_subscription = 1
  8973.             if @no_row <> 0
  8974.                 RETURN(0)
  8975.         END
  8976.  
  8977. SelectPubs:
  8978.  
  8979.     CREATE TABLE #tab1 (
  8980.         id                      int                 identity NOT NULL,
  8981.         name                    sysname             collate database_default not null,
  8982.         description             nvarchar(255)       collate database_default null,
  8983.         status                  tinyint             NOT NULL,
  8984.         retention               int                 NULL,
  8985.         sync_mode               tinyint             NULL,
  8986.         allow_push              int                 NOT NULL,
  8987.         allow_pull              int                 NOT NULL,
  8988.         allow_anonymous         int                 NOT NULL,
  8989.         centralized_conflicts   int                 NOT NULL,
  8990.         priority                float(8)            NOT NULL,
  8991.         snapshot_ready          tinyint             NOT NULL,
  8992.         publication_type        int                 NULL,
  8993.         pubid                   uniqueidentifier    NOT NULL,
  8994.         snapshot_jobid          binary(16)          NULL,
  8995.         enabled_for_internet    int                 NULL,
  8996.         dynamic_filters         int                 NULL,
  8997.         has_subscription        bit                 NULL,
  8998.         -- Portable snapshot support
  8999.         snapshot_in_defaultfolder       bit default 1       NOT NULL,
  9000.         alt_snapshot_folder     nvarchar(255)       collate database_default null,
  9001.         -- Pre/post-snapshot commands
  9002.         pre_snapshot_script     nvarchar(255)       collate database_default null,
  9003.         post_snapshot_script    nvarchar(255)       collate database_default null,
  9004.         -- Snapshot compression
  9005.         compress_snapshot       bit default 0       NOT NULL,
  9006.         -- Post 7.0 FTP support
  9007.         ftp_address             sysname             collate database_default null,
  9008.         ftp_port                int                 NOT NULL,
  9009.         ftp_subdirectory        nvarchar(255)       collate database_default null,
  9010.         ftp_login               sysname             collate database_default null,
  9011.         conflict_retention        int                    NULL,
  9012.         keep_partition_changes    int                    NULL,
  9013.         allow_subscription_copy int                 NULL,
  9014.         allow_synctoalternate     int                 NULL,
  9015.         validate_subscriber_info nvarchar(500)        collate database_default null,
  9016.         backward_comp_level        int                    not null default 10, --defaulted to 70 server
  9017.         publish_to_activedirectory            bit                    null,
  9018.         max_concurrent_merge    int                    NULL,
  9019.         max_concurrent_dynamic_snapshots int  NOT NULL default 0
  9020.         )
  9021.  
  9022.     /* This is valid at all sites - used for decentralized conflicts */
  9023.     IF LOWER(@reserved collate SQL_Latin1_General_CP1_CS_AS) = 'internal'
  9024.     begin
  9025.         INSERT into #tab1(name, description, status, retention, sync_mode, 
  9026.                 allow_push, allow_pull, allow_anonymous, centralized_conflicts, 
  9027.                 priority, snapshot_ready, publication_type, pubid, snapshot_jobid, 
  9028.                 enabled_for_internet, 
  9029.                 dynamic_filters, snapshot_in_defaultfolder, alt_snapshot_folder, pre_snapshot_script,
  9030.                 post_snapshot_script, compress_snapshot, ftp_address, ftp_port, 
  9031.                 ftp_subdirectory, ftp_login, conflict_retention, 
  9032.                 keep_partition_changes, allow_subscription_copy, allow_synctoalternate, 
  9033.                 validate_subscriber_info,backward_comp_level, publish_to_activedirectory, max_concurrent_merge, max_concurrent_dynamic_snapshots)
  9034.         select  pubs.name, pubs.description, pubs.status, pubs.retention, pubs.sync_mode, 
  9035.                 pubs.allow_push, pubs.allow_pull, pubs.allow_anonymous, pubs.centralized_conflicts, 
  9036.                 subs.priority, pubs.snapshot_ready, pubs.publication_type, pubs.pubid, replinfo.snapshot_jobid,
  9037.                 pubs.enabled_for_internet, 
  9038.                 pubs.dynamic_filters,
  9039.                 pubs.snapshot_in_defaultfolder,
  9040.                 pubs.alt_snapshot_folder,
  9041.                 pubs.pre_snapshot_script,
  9042.                 pubs.post_snapshot_script,
  9043.                 pubs.compress_snapshot,
  9044.                 pubs.ftp_address,
  9045.                 pubs.ftp_port,
  9046.                 pubs.ftp_subdirectory,
  9047.                 pubs.ftp_login,
  9048.                 pubs.conflict_retention,
  9049.                 pubs.keep_before_values,
  9050.                 pubs.allow_subscription_copy,
  9051.                 pubs.allow_synctoalternate,
  9052.                 pubs.validate_subscriber_info,
  9053.                 pubs.backward_comp_level,
  9054.                 case when pubs.ad_guidname is NULL then 0 else 1 end,
  9055.                 pubs.max_concurrent_merge,
  9056.                 pubs.max_concurrent_dynamic_snapshots
  9057.         FROM    sysmergesubscriptions   subs,
  9058.                 sysmergepublications    pubs,
  9059.                 MSmerge_replinfo        replinfo
  9060.                 WHERE pubs.name LIKE @publication
  9061.                     AND UPPER(pubs.publisher)=UPPER(@@servername) 
  9062.                     AND pubs.publisher_db=db_name()
  9063.                     AND subs.subid = pubs.pubid
  9064.                     AND replinfo.repid = pubs.pubid
  9065.                     AND subs.subscriber_type = 1
  9066.                     and (1 = {fn ISPALUSER(pubs.pubid)} or
  9067.                             1 = is_member('replmonitor'))
  9068.         ORDER BY name
  9069.     end
  9070.     /* This is valid only at publishers and republishers */
  9071.     else
  9072.     begin
  9073.         INSERT into #tab1(name, description, status, retention, sync_mode, 
  9074.                 allow_push, allow_pull, allow_anonymous, centralized_conflicts, 
  9075.                 priority, snapshot_ready, publication_type, pubid, snapshot_jobid, 
  9076.                 enabled_for_internet,
  9077.                 dynamic_filters, has_subscription,
  9078.                 snapshot_in_defaultfolder, alt_snapshot_folder, pre_snapshot_script, 
  9079.                 post_snapshot_script, compress_snapshot, ftp_address,
  9080.                 ftp_port, ftp_subdirectory, ftp_login, conflict_retention, 
  9081.                 keep_partition_changes, allow_subscription_copy, allow_synctoalternate, 
  9082.                 validate_subscriber_info, backward_comp_level, publish_to_activedirectory,max_concurrent_merge,max_concurrent_dynamic_snapshots)
  9083.         select  pubs.name, pubs.description, pubs.status, pubs.retention, pubs.sync_mode, 
  9084.                 pubs.allow_push, pubs.allow_pull, pubs.allow_anonymous, pubs.centralized_conflicts, 
  9085.                 subs.priority, pubs.snapshot_ready, pubs.publication_type, pubs.pubid, replinfo.snapshot_jobid,
  9086.                 pubs.enabled_for_internet,
  9087.                 pubs.dynamic_filters, case when exists (select * from sysmergesubscriptions where pubid<>subid and pubid in 
  9088.                                             (select in_pubs.pubid from sysmergepublications in_pubs where in_pubs.name = pubs.name 
  9089.                                                 and UPPER(in_pubs.publisher)=UPPER(@@servername) and in_pubs.publisher_db=db_name()))
  9090.                                       then 1
  9091.                                       else 0 end,
  9092.                 pubs.snapshot_in_defaultfolder, pubs.alt_snapshot_folder,
  9093.                 pubs.pre_snapshot_script, pubs.post_snapshot_script,
  9094.                 pubs.compress_snapshot, pubs.ftp_address,
  9095.                 pubs.ftp_port, pubs.ftp_subdirectory,
  9096.                 pubs.ftp_login,
  9097.                 pubs.conflict_retention,
  9098.                 pubs.keep_before_values,
  9099.                 pubs.allow_subscription_copy,
  9100.                 pubs.allow_synctoalternate,
  9101.                 pubs.validate_subscriber_info,
  9102.                 pubs.backward_comp_level,
  9103.                 case when pubs.ad_guidname is NULL then 0 else 1 end ,
  9104.                 pubs.max_concurrent_merge,
  9105.                 pubs.max_concurrent_dynamic_snapshots
  9106.         FROM    sysmergesubscriptions   subs,
  9107.                 sysmergepublications    pubs,
  9108.                 MSmerge_replinfo        replinfo
  9109.                 WHERE pubs.name LIKE @publication
  9110.                      and UPPER(pubs.publisher)=UPPER(@@servername) 
  9111.                      and pubs.publisher_db=db_name()
  9112.                     AND subs.subid = pubs.pubid
  9113.                     AND replinfo.repid = pubs.pubid
  9114.                     AND subs.subscriber_type = 1
  9115.                     AND subs.srvid = @our_srvid 
  9116.                     AND subs.db_name = db_name()
  9117.         ORDER BY name
  9118.     end
  9119.     if @@ERROR <> 0 
  9120.         RETURN (1)
  9121.  
  9122.     update #tab1 set snapshot_ready=0 where snapshot_ready>1
  9123.     if @@ERROR<>0
  9124.         RETURN (1)
  9125.         
  9126.     select * FROM #tab1
  9127.         where 1 = {fn ISPALUSER(pubid)} or
  9128.               1 = is_member('replmonitor')
  9129.  
  9130.     RETURN (0)
  9131. go
  9132. exec dbo.sp_MS_marksystemobject sp_helpmergepublication 
  9133. go
  9134.  
  9135. grant execute on dbo.sp_helpmergepublication to public
  9136. go
  9137.  
  9138.  
  9139. raiserror('Creating procedure sp_dropmergepublication', 0,1)
  9140. GO
  9141.  
  9142. CREATE PROCEDURE sp_dropmergepublication(
  9143.         @publication sysname,      /* The publication name */
  9144.         @ignore_distributor bit = 0,
  9145.         @reserved bit = 0
  9146.         ) AS
  9147.  
  9148.     set nocount on
  9149.     /*
  9150.     ** Declarations.
  9151.     */
  9152.     declare @ad_guidname        sysname
  9153.     declare @pubid              uniqueidentifier
  9154.     declare @article            sysname
  9155.     declare @cmd                nvarchar(255)
  9156.     declare @retcode            int
  9157.     declare @distproc           nvarchar(300)
  9158.     declare @distributor        sysname
  9159.     declare @distribdb          sysname
  9160.     declare @working_dir        varchar(255)
  9161.     declare @working_dir_drive  varchar(255)
  9162.     declare @pub_dir            nvarchar(255)
  9163.     declare @db_name            sysname
  9164.     declare @implicit_transaction    int
  9165.     declare @close_cursor_at_commit int
  9166.     declare @dynamic_filters        bit
  9167.     declare @alt_snapshot_folder nvarchar(255)
  9168.     declare @pub_alt_snapshot_folder nvarchar(255)
  9169.  
  9170.     select @close_cursor_at_commit = 0
  9171.     select @implicit_transaction = 0
  9172.     /*
  9173.     ** Save setting values first before changing them
  9174.     */
  9175.     IF (@reserved = 0)
  9176.     BEGIN
  9177.         SELECT @implicit_transaction = @@options & 2
  9178.         SELECT @close_cursor_at_commit = @@options & 4
  9179.         SET IMPLICIT_TRANSACTIONS OFF
  9180.         SET CURSOR_CLOSE_ON_COMMIT OFF
  9181.     END
  9182.  
  9183.     set @ad_guidname = NULL
  9184.     /*
  9185.     ** Initializations.
  9186.     */  
  9187.     select @db_name = db_name()
  9188.  
  9189.     /*
  9190.     ** Security Check
  9191.     */
  9192.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  9193.     IF @@ERROR <> 0 or @retcode <> 0
  9194.         return (1)
  9195.  
  9196.     /* make sure current database is enabled for merge replication */
  9197.     exec @retcode=dbo.sp_MSCheckmergereplication
  9198.     if @@ERROR<>0 or @retcode<>0
  9199.         return (1)
  9200.  
  9201.     if LOWER(@publication) = 'all'
  9202.         BEGIN
  9203.  
  9204.             declare hC1 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT name 
  9205.                 FROM sysmergepublications where UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name() 
  9206.                     FOR READ ONLY
  9207.             
  9208.             OPEN hC1
  9209.             FETCH hC1 INTO @publication
  9210.             WHILE (@@fetch_status <> -1)
  9211.                 BEGIN
  9212.                     EXECUTE dbo.sp_dropmergepublication @publication=@publication,
  9213.                         @ignore_distributor = @ignore_distributor,
  9214.                         @reserved = 1
  9215.  
  9216.                     FETCH hC1 INTO @publication
  9217.                 END
  9218.             CLOSE hC1
  9219.             DEALLOCATE hC1
  9220.             RETURN (0)
  9221.         END
  9222.  
  9223.     if @publication IS NULL
  9224.         BEGIN
  9225.             RAISERROR (14003, 16, -1)
  9226.             RETURN (1)
  9227.         END
  9228.     /*
  9229.     ** Get the @pubid.
  9230.     */
  9231.     if NOT EXISTS (select * FROM sysmergepublications 
  9232.         WHERE name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name())
  9233.         BEGIN
  9234.             RAISERROR (20026, 16, -1, @publication)
  9235.             RETURN (1)
  9236.         END
  9237.     select @pubid = pubid,
  9238.            @dynamic_filters = @dynamic_filters,
  9239.            @alt_snapshot_folder = alt_snapshot_folder 
  9240.       FROM sysmergepublications 
  9241.         WHERE name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  9242.  
  9243.     select @ad_guidname=ad_guidname FROM sysmergepublications 
  9244.             WHERE name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()    
  9245.     
  9246.     /* 
  9247.     ** Ignore external publications
  9248.     */
  9249.     if exists (select * from sysmergesubscriptions where subid=@pubid 
  9250.         and pubid=@pubid and db_name<>db_name())
  9251.     RETURN (0)
  9252.  
  9253.     /*
  9254.     ** Check to make sure that there are push or pull subscriptions on the publication.
  9255.     */
  9256.     if EXISTS (select * FROM sysmergesubscriptions  subs, 
  9257.                     sysmergepublications                pubs, 
  9258.                     MSmerge_replinfo                    repinfo
  9259.                 WHERE   pubs.name = @publication
  9260.                     AND UPPER(pubs.publisher)=UPPER(@@servername) 
  9261.                     AND pubs.publisher_db=db_name()
  9262.                     AND subs.pubid = pubs.pubid
  9263.                     AND subs.status <> 2  -- Having a deleted subscription row is fine
  9264.                     AND repinfo.repid <> @pubid
  9265.                     AND subs.subid <> subs.partnerid)
  9266.         BEGIN
  9267.             RAISERROR (14005, 16, -1)
  9268.             RETURN (1)
  9269.         END
  9270.  
  9271.     -- drop the database role that contains users who have access to the publication
  9272.     -- this has to be done outside the transaction since role operations cannot be
  9273.     -- done in transaction
  9274.     declare @role sysname
  9275.     declare @pubidstr nvarchar(40)
  9276.     declare @member sysname
  9277.     
  9278.     exec dbo.sp_MSguidtostr @pubid, @pubidstr output
  9279.     set @role = 'MSmerge_' + @pubidstr
  9280.  
  9281.     if exists (select * from dbo.sysusers where issqlrole=1 and name=@role)
  9282.     begin
  9283.         declare role_members cursor fast_forward
  9284.         for select u.name as MemberName
  9285.                 from dbo.sysusers u, dbo.sysusers g, dbo.sysmembers m
  9286.                 where g.name = @role
  9287.                     and g.uid = m.groupuid
  9288.                     and g.issqlrole = 1
  9289.                     and u.uid = m.memberuid
  9290.                     
  9291.         open role_members 
  9292.         fetch role_members into @member
  9293.         while @@fetch_status <> -1
  9294.         begin
  9295.             exec @retcode = dbo.sp_droprolemember @role, @member
  9296.             if (@retcode <> 0 or @@error <> 0)
  9297.             BEGIN
  9298.                 close role_members
  9299.                 deallocate role_members
  9300.                 RAISERROR (14005, 16, -1)
  9301.                 RETURN (1)
  9302.             END
  9303.             fetch role_members into @member
  9304.         end
  9305.         close role_members
  9306.         deallocate role_members
  9307.         
  9308.         exec @retcode = dbo.sp_droprole @role
  9309.         if (@retcode <> 0 or @@error <> 0)
  9310.         BEGIN
  9311.             RAISERROR (14005, 16, -1)
  9312.             RETURN (1)
  9313.         END
  9314.     end
  9315.     
  9316.  
  9317.     begin tran
  9318.     save TRANSACTION dropmergepublication
  9319.  
  9320.     /*
  9321.     ** delete on-demand user script, if any
  9322.     */
  9323.     if exists (select * from sysmergeschemachange where schematype=46 and pubid=@pubid)
  9324.         begin
  9325.             exec @retcode=sp_MSremove_userscript @pubid, 1
  9326.             --we may not want to do error checking here
  9327.         end
  9328.     
  9329.     /*
  9330.     ** Delete all articles from the publication.
  9331.     */
  9332.  
  9333.     update sysmergepublications set snapshot_ready=0 where pubid=@pubid --so that articles can be dropped
  9334.     if @@ERROR<>0
  9335.         goto FAILURE
  9336.     EXECUTE @retcode = dbo.sp_dropmergearticle @publication = @publication, @article = 'all',
  9337.         @ignore_distributor = @ignore_distributor
  9338.  
  9339.     if @@ERROR <> 0 OR @retcode <> 0
  9340.         begin
  9341.             RAISERROR (20040, 16, -1, @publication)
  9342.             goto FAILURE
  9343.         end
  9344.  
  9345.     /*
  9346.     ** Delete sync task of Publication.
  9347.     */
  9348.     execute @retcode = dbo.sp_MSdropmergepub_snapshot @publication = @publication,
  9349.         @ignore_distributor = @ignore_distributor
  9350.  
  9351.     if @@ERROR <> 0 OR @retcode <> 0
  9352.         begin
  9353.             RAISERROR (20010, 16, -1, @publication)
  9354.             goto FAILURE
  9355.         end
  9356.  
  9357.     /*
  9358.     ** Remove my own subscription from sysmergesubscriptions.
  9359.     */
  9360.     if exists (select * from sysmergesubscriptions where subid = @pubid)
  9361.         begin
  9362.             DELETE from sysmergesubscriptions WHERE subid = @pubid
  9363.             if @@ERROR <> 0
  9364.                 goto FAILURE
  9365.         end         
  9366.  
  9367.     if exists (select * from MSmerge_replinfo where repid = @pubid)
  9368.         begin
  9369.             DELETE from MSmerge_replinfo WHERE repid = @pubid
  9370.             if @@ERROR <> 0
  9371.                 goto FAILURE
  9372.         end             
  9373.  
  9374.     /*
  9375.     ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
  9376.     */
  9377.     if @ignore_distributor = 0
  9378.     begin
  9379.         /*
  9380.         ** Get distribution server information for remote RPC call.
  9381.         */
  9382.         EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
  9383.                                            @distribdb = @distribdb OUTPUT,
  9384.                                            @directory = @working_dir OUTPUT
  9385.         IF @@ERROR <> 0 OR  @retcode <> 0
  9386.             BEGIN
  9387.                 RAISERROR (14071, 16, -1)
  9388.                 goto FAILURE
  9389.             END
  9390.  
  9391.         /*
  9392.         ** Drop the publication info from the distributor
  9393.         */
  9394.         select @distproc = RTRIM(@distributor) + '.' + @distribdb + 
  9395.             '.dbo.sp_MSdrop_publication'
  9396.         EXECUTE @retcode = @distproc
  9397.             @publisher = @@SERVERNAME,
  9398.             @publisher_db = @db_name,
  9399.             @publication = @publication
  9400.  
  9401.         if @@ERROR <> 0 OR @retcode <> 0
  9402.         begin
  9403.             goto FAILURE
  9404.         end
  9405.  
  9406.         /*
  9407.         ** If alternate snapshot folder is specified for this publication,
  9408.         ** try to remove the publication's snapshot folder underneath the
  9409.         ** the alternate snapshot location in Distributor's context
  9410.         */
  9411.         if @alt_snapshot_folder is not null and
  9412.            @alt_snapshot_folder <> N''
  9413.         begin
  9414.  
  9415.             /* Append publication specific folder name */
  9416.             if substring(@alt_snapshot_folder,len(@alt_snapshot_folder),1)<>
  9417.                 N'\' 
  9418.             begin
  9419.                 select @alt_snapshot_folder = @alt_snapshot_folder + N'\'
  9420.             end 
  9421.  
  9422.             -- UNC version
  9423.             select @pub_alt_snapshot_folder = @alt_snapshot_folder + N'unc\' + fn_replcomposepublicationsnapshotfolder(@@servername,@db_name,@publication) collate database_default
  9424.             select @distproc = fn_replquotename(RTRIM(@distributor)) collate database_default + '.'  + fn_replquotename(@distribdb) collate database_default + 
  9425.                 '.dbo.sp_MSreplremoveuncdir'
  9426.             -- Ignore errors as the snapshot folder may not exist at all
  9427.             EXECUTE @distproc
  9428.                 @dir = @pub_alt_snapshot_folder
  9429.  
  9430.             -- FTP-enabled version
  9431.             select @pub_alt_snapshot_folder = @alt_snapshot_folder + N'ftp\' + fn_replcomposepublicationsnapshotfolder(@@servername,@db_name,@publication) collate database_default
  9432.             select @distproc = fn_replquotename(RTRIM(@distributor)) collate database_default + '.'  + fn_replquotename(@distribdb) collate database_default + 
  9433.                 '.dbo.sp_MSreplremoveuncdir'
  9434.             -- Ignore errors as the snapshot folder may not exist at all
  9435.             EXECUTE @distproc
  9436.                 @dir = @pub_alt_snapshot_folder
  9437.         end         
  9438.     end
  9439.  
  9440.     /* Remove all dynamic snapshot jobs of this publication */
  9441.     exec @retcode = sp_MSdropmergedynamicsnapshotjob 
  9442.         @publication = @publication,
  9443.         @ignore_distributor = @ignore_distributor
  9444.  
  9445.     if @@ERROR <> 0 OR @retcode <> 0
  9446.     begin
  9447.         goto FAILURE
  9448.     end
  9449.  
  9450.     /*
  9451.     ** Execute the cleanup routine for the publication
  9452.     */
  9453.     exec dbo.sp_MSpublicationcleanup @publisher=@@SERVERNAME, 
  9454.             @publisher_db = @db_name,
  9455.             @publication = @publication
  9456.     
  9457.     if @@ERROR <> 0
  9458.         goto FAILURE
  9459.  
  9460.     DECLARE @retval  INT
  9461.     EXECUTE @retval = master.dbo.xp_MSADEnabled
  9462.     if @ad_guidname is not NULL 
  9463.     begin
  9464.         if @retval = 0
  9465.         begin
  9466.             exec @retcode=master.dbo.sp_ActiveDirectory_Obj 'DELETE', 'PUBLICATION', @publication, @db_name, @ad_guidname
  9467.             if @@ERROR<>0 or @retcode<>0
  9468.             begin
  9469.                 raiserror(21369, 16, -1, @publication)
  9470.                 goto FAILURE
  9471.             end
  9472.         end
  9473.         else
  9474.         begin
  9475.             RAISERROR(21254, 16, -1, @publication)
  9476.             GOTO FAILURE
  9477.         end
  9478.     end
  9479.  
  9480.     COMMIT TRANSACTION
  9481.     /*
  9482.     ** Set back original settings
  9483.     */    
  9484.     IF @reserved = 0
  9485.     BEGIN
  9486.         IF @implicit_transaction <>0 
  9487.             SET IMPLICIT_TRANSACTIONS ON
  9488.         IF @close_cursor_at_commit <>0 
  9489.             SET CURSOR_CLOSE_ON_COMMIT ON
  9490.     END
  9491.     return (0)
  9492.  
  9493. FAILURE:            
  9494.     RAISERROR (14006, 16, -1)
  9495.     /* UNDONE : This code is specific to 6.X nested transaction semantics */
  9496.     if @@TRANCOUNT > 0
  9497.     begin
  9498.         ROLLBACK TRANSACTION dropmergepublication
  9499.         COMMIT TRANSACTION
  9500.     end
  9501.     /*
  9502.     ** Set back original settings
  9503.     */    
  9504.     IF @reserved = 0
  9505.     BEGIN
  9506.         IF @implicit_transaction <>0 
  9507.             SET IMPLICIT_TRANSACTIONS ON
  9508.         IF @close_cursor_at_commit <>0 
  9509.             SET CURSOR_CLOSE_ON_COMMIT ON
  9510.     END        
  9511.     RETURN (1)
  9512. go
  9513. exec dbo.sp_MS_marksystemobject sp_dropmergepublication
  9514. go
  9515.  
  9516. grant execute on dbo.sp_dropmergepublication to public
  9517. go
  9518.  
  9519. raiserror('Creating procedure sp_mergearticlecolumn', 0, 1)
  9520. GO
  9521.  
  9522. CREATE PROCEDURE sp_mergearticlecolumn (
  9523.         @publication sysname,           /* The publication name */
  9524.         @article sysname,               /* The article name */
  9525.         @column sysname = NULL,         /* The column name */
  9526.         @operation nvarchar(4) = 'add',      /* Add or delete a column */
  9527.         @schema_replication nvarchar(5) = 'false',    /* reserved for internal use */
  9528.         @force_invalidate_snapshot bit = 0,    /* Force invalidate existing snapshot */
  9529.         @force_reinit_subscription bit = 0    /* Force reinit subscription */
  9530.         ) AS
  9531.  
  9532.     SET NOCOUNT ON
  9533.     /*
  9534.     ** Declarations.
  9535.     */
  9536.     declare @mergepublish    int
  9537.     declare @iscomputed        int
  9538.     declare @xtype            int
  9539.     declare @sync_mode        int
  9540.     declare @index_cnt        int
  9541.     declare @v_unique_constraint            int
  9542.     declare @v_unique_index            int
  9543.     declare @indid            int
  9544.     declare @in_partition     bit
  9545.     declare @colid    int
  9546.     DECLARE @cnt int, @idx int  /* Loop counter, index */
  9547.     DECLARE @columnid smallint   /* Columnid-1 = bit to set */
  9548.     DECLARE @columns binary(128)         /* Temporary storage for the converted column */
  9549.     DECLARE @pubid uniqueidentifier                  /* Publication identification number */
  9550.     DECLARE @retcode int                /* Return code for stored procedures */
  9551.     DECLARE @artid uniqueidentifier
  9552.     declare @object_view     sysname
  9553.     declare @filter_clause nvarchar(1000)
  9554.     DECLARE @objid int            /* Article base table id */    
  9555.     declare @tmp_artid    uniqueidentifier
  9556.     declare @tmp_object    sysname
  9557.     declare @publisher    sysname
  9558.     declare @publisher_db    sysname
  9559.     declare @pkkey        sysname
  9560.     declare @conflict_table    sysname
  9561.     declare @status_value    int
  9562.     declare @column_list    nvarchar(4000)
  9563.     declare @ins_conflict_proc sysname
  9564.     declare @qual_source_object    nvarchar(270)
  9565.     declare @qual_object_view    nvarchar(270)
  9566.     declare @qual_tmp_object    nvarchar(270)
  9567.     declare @source_object    nvarchar(300)
  9568.     declare @v_foreign_key int
  9569.     declare @quoted_source_object nvarchar(270)
  9570.     select @publisher = @@SERVERNAME
  9571.     select @publisher_db = db_name()
  9572.     /*
  9573.     ** Security Check
  9574.     */
  9575.     exec @retcode = dbo.sp_MSreplcheck_publish
  9576.     if @@ERROR <> 0 or @retcode <> 0
  9577.         return(1)
  9578.  
  9579.     select @mergepublish = 0x4000
  9580.     select @v_unique_index      = 2         -- status in sysindexes
  9581.     select @v_foreign_key = 3            -- status in sysconstraints
  9582.     select @v_unique_constraint      = 4096 --status in sysindexes
  9583.  
  9584.     /*
  9585.     ** Check to see if the database has been activated for publication.
  9586.     */
  9587.  
  9588.     IF ( (SELECT category & 4 FROM master..sysdatabases WHERE name = DB_NAME() collate database_default) = 0 )
  9589.     BEGIN
  9590.         RAISERROR (14013, 16, -1)
  9591.         RETURN (1)
  9592.     END
  9593.  
  9594.     /*
  9595.     ** Parameter Check:  @publication.
  9596.     ** Make sure that the publication exists and that it conforms to the
  9597.     ** rules for identifiers.
  9598.     */
  9599.  
  9600.     IF @publication IS NULL
  9601.         BEGIN
  9602.             RAISERROR (14043, 16, -1, '@publication')
  9603.             RETURN (1)
  9604.         END
  9605.  
  9606.     EXECUTE @retcode = dbo.sp_validname @publication
  9607.     IF @retcode <> 0 or @@ERROR<>0
  9608.             RETURN (1)
  9609.  
  9610.     SELECT @pubid = pubid, @sync_mode = sync_mode FROM sysmergepublications WHERE name = @publication 
  9611.                                                         and LOWER(publisher)=LOWER(@publisher)
  9612.                                                         and publisher_db = @publisher_db
  9613.                                                                     
  9614.     IF @pubid IS NULL
  9615.         BEGIN
  9616.             RAISERROR (20026, 11, -1, @publication)
  9617.             RETURN (1)
  9618.         END
  9619.  
  9620.     /*
  9621.     ** Parameter Check:  @article.
  9622.     ** Check to make sure that the article exists in the publication.
  9623.     */
  9624.  
  9625.     IF @article IS NULL
  9626.         BEGIN
  9627.             RAISERROR (14043, 16, -1, '@article')
  9628.             RETURN (1)
  9629.         END
  9630.  
  9631.     EXECUTE @retcode = dbo.sp_validname @article
  9632.     IF @retcode <> 0 or @@ERROR<>0
  9633.             RETURN (1)
  9634.  
  9635.     /*
  9636.     ** Make sure the article exists.
  9637.     */
  9638.     SELECT @artid = artid FROM sysmergearticles
  9639.        WHERE pubid = @pubid AND name = @article
  9640.     IF @artid IS NULL
  9641.         BEGIN
  9642.             RAISERROR (20027, 16, -1, @article)
  9643.             RETURN (1)
  9644.         END
  9645.     
  9646.     /*
  9647.     ** Parameter Check:  @column.
  9648.     ** Check to make sure that the column exists and conforms to the rules
  9649.     ** for identifiers.
  9650.     */
  9651.  
  9652.     IF @column IS NOT NULL
  9653.         BEGIN
  9654.             EXECUTE @retcode = dbo.sp_validname @column
  9655.             IF @@ERROR <> 0 OR @retcode <> 0
  9656.             RETURN (1)
  9657.         END
  9658.  
  9659.     /*
  9660.     ** Parameter Check:  @operation.
  9661.     ** The operation can be either 'add' or 'drop'.
  9662.     */
  9663.     IF LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('add', 'drop')
  9664.         BEGIN
  9665.             RAISERROR (14019, 16, -1)
  9666.             RETURN (1)
  9667.         END
  9668.         
  9669.     /*
  9670.     ** column name can not be null for 'drop' operation. OK for 'add' operation
  9671.     */
  9672.     IF LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS)='drop' and @column is NULL
  9673.         BEGIN
  9674.             RAISERROR(14043, 16, -1, '@column')
  9675.             RETURN (1)
  9676.         END    
  9677.     /*
  9678.     ** Can not drop non-identity, non-timestamp, non-computed columns that are not nullable and have no default value
  9679.     */
  9680.     SELECT @status_value=status, @objid = objid, 
  9681.         @source_object = object_name(objid) FROM sysmergearticles WHERE artid = @artid
  9682.     select @colid=colid from syscolumns where id=@objid and name=@column
  9683.     if not exists (select * from syscolumns where id = @objid and name=@column and (isnullable=1 
  9684.                     OR type_name(xtype)='timestamp' OR iscomputed=1))
  9685.         and not exists (select * from sysconstraints where id=@objid and colid=@colid and status & 5 = 5)
  9686.             and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS)='drop' and LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='false'
  9687.             and ColumnProperty(@objid, @column, 'IsIdentity') <> 1
  9688.         BEGIN
  9689.             RAISERROR(21165, 16, -1, @column)
  9690.             return (1)
  9691.         END
  9692.         
  9693.     
  9694.     if LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
  9695.     begin        
  9696.         select @indid = indid from sysindexes where id = @objid and (status & 2048) <> 0    /* PK index */
  9697.         select @index_cnt = 1
  9698.         while (@index_cnt <= 16)
  9699.             begin
  9700.                 select @pkkey = INDEX_COL(@source_object, @indid, @index_cnt)
  9701.                 if @pkkey is NULL
  9702.                     break
  9703.                 if @pkkey=@column
  9704.                     begin
  9705.                         raiserror(21250, 16, -1, @column)
  9706.                         return (1)
  9707.                     end
  9708.                 select @index_cnt = @index_cnt + 1
  9709.             end
  9710.     
  9711.         /*
  9712.         ** Check for unique index defined on this column - to disallow such a column from being dropped
  9713.         */    
  9714.         if exists (select * from sysindexes where id=@objid 
  9715.                     and (status & @v_unique_index = @v_unique_index 
  9716.                         or status & @v_unique_constraint = @v_unique_constraint))
  9717.         begin
  9718.             declare @keys varbinary(816)
  9719.             declare @i         int
  9720.             declare #check_unique CURSOR LOCAL FAST_FORWARD for 
  9721.             select indid from sysindexes where id=@objid 
  9722.                 and (status & @v_unique_index = @v_unique_index 
  9723.                     or status & @v_unique_constraint = @v_unique_constraint)
  9724.             open #check_unique
  9725.             fetch #check_unique into @indid
  9726.             while (@@fetch_status<>-1)
  9727.             begin
  9728.                 SELECT @i = 1
  9729.                 WHILE (@i <= 16)
  9730.                 BEGIN
  9731.                         SELECT @pkkey = INDEX_COL(@source_object, @indid, @i)
  9732.                         if @pkkey is NULL
  9733.                             break
  9734.                         if @pkkey=@column
  9735.                         BEGIN
  9736.                             if LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='true'
  9737.                                 raiserror(21265, 16, -1, @column, @source_object)
  9738.                             else
  9739.                                 raiserror(21347, 16, -1, @column)                            
  9740.                             close #check_unique
  9741.                             deallocate #check_unique
  9742.                             return (1)
  9743.                         END
  9744.                         select @i = @i + 1
  9745.                 END    
  9746.                 fetch #check_unique into @indid
  9747.             end
  9748.             close #check_unique
  9749.             deallocate #check_unique
  9750.         end
  9751.  
  9752.         /*
  9753.         ** Check for foreign key constraints
  9754.         */
  9755.         if exists (select * from sysconstraints where status & @v_foreign_key=@v_foreign_key and id=@objid)
  9756.         begin
  9757.             if @column in (select name from syscolumns where id=@objid and colid in
  9758.                 (select colid from sysconstraints where status & @v_foreign_key=@v_foreign_key and id=@objid))
  9759.             begin
  9760.                 raiserror(21513, 16, -1, @column)
  9761.                 return (1)
  9762.             end
  9763.         end
  9764.     end
  9765.  
  9766.     begin tran
  9767.     save TRANSACTION articlecolumn
  9768.  
  9769.     /*
  9770.     ** Make sure that the column <columns> is not NULL - if NULL set to 0x00.
  9771.     */
  9772.     SELECT @columns = columns FROM sysmergearticles WHERE artid = @artid and pubid=@pubid
  9773.     IF @columns IS NULL
  9774.         UPDATE sysmergearticles SET columns = 0x00 WHERE artid = @artid and pubid=@pubid
  9775.     
  9776.     /*
  9777.     ** If no columns are specified, or if NULL is specified, set all
  9778.     ** the bits in the 'columns' column so all columns will be included, 
  9779.     */
  9780.     IF @column IS NULL
  9781.     BEGIN
  9782.         SELECT @cnt = max(colid), @idx = 1 FROM syscolumns WHERE id = @objid 
  9783.         SELECT @columns = NULL
  9784.         WHILE @idx <= @cnt
  9785.         BEGIN
  9786.             /* to make sure column holes will not be included */
  9787.             if exists (select * from syscolumns where colid=@idx and id=@objid and 
  9788.                 (@sync_mode=0 OR (iscomputed<>1 and type_name(xtype) <>'timestamp')))
  9789.                 begin
  9790.                     exec sp_MSsetbit @bm=@columns OUTPUT, @coltoadd=@idx, @toset = 1
  9791.                     if @@ERROR<>0 or @retcode<>0
  9792.                         goto FAILURE
  9793.                     update syscolumns set colstat=colstat | @mergepublish where id=@objid and colid=@idx
  9794.                     if @@ERROR<>0
  9795.                         goto FAILURE
  9796.  
  9797.                 end
  9798.             SELECT @idx = @idx + 1
  9799.         END
  9800.         UPDATE sysmergearticles SET columns = @columns WHERE name = @article AND pubid = @pubid
  9801.         if @sync_mode=1 and exists (select * from syscolumns where id=@objid and (iscomputed=1 or type_name(xtype)='timestamp'))
  9802.             UPDATE sysmergearticles SET vertical_partition = 1 WHERE name = @article AND pubid = @pubid
  9803.     END
  9804.     ELSE
  9805.     BEGIN
  9806.         /* if @column is NULL, meanning all columns are in, do not bump up version to Shiloh. */
  9807.         if LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='false'
  9808.             raiserror(21351, 10, -1, @publication)
  9809.         else
  9810.             raiserror(21352, 10, -1, @publication)
  9811.         exec @retcode = sp_MSBumpupCompLevel @pubid, 40
  9812.         if @@ERROR<>0 or @retcode<>0
  9813.             GOTO FAILURE
  9814.  
  9815.         SELECT @columnid = colid, @iscomputed=iscomputed, @xtype=xtype  
  9816.             FROM syscolumns WHERE id = @objid AND name = @column
  9817.         IF ((@@error <> 0) OR (@columnid IS NULL))
  9818.         BEGIN
  9819.             RAISERROR (21166, 16, -1, @column)
  9820.             GOTO FAILURE
  9821.         END
  9822.  
  9823.         /*
  9824.         ** for character mode publications, we do not allow adding computed column or timestamp columns
  9825.         ** into the vertical parititioning. 
  9826.         */
  9827.         if @sync_mode=1 and (@iscomputed = 1 or type_name(@xtype) ='timestamp') and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'add'
  9828.         begin
  9829.             if LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='false'
  9830.                 begin
  9831.                     raiserror(21269, 16, -1)
  9832.                     GOTO FAILURE
  9833.                 end
  9834.             else
  9835.             begin    
  9836.                 if @@TRANCOUNT >0 
  9837.                 begin
  9838.                     ROLLBACK TRANSACTION articlecolumn
  9839.                     COMMIT TRAN
  9840.                 end
  9841.                 return (0)
  9842.             end
  9843.         end
  9844.         
  9845.         if ColumnProperty(@objid, @column, 'isrowguidcol') = 1 and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
  9846.         begin
  9847.             RAISERROR(21162, 16, -1)
  9848.             GOTO FAILURE
  9849.         end
  9850.  
  9851.         exec @in_partition = sp_MStestbit @bm=@columns, @coltotest=@columnid
  9852.  
  9853.         if @in_partition=1 and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'add' and LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='false'
  9854.         begin
  9855.             RAISERROR(21335, 10, -1, @column)
  9856.             GOTO FAILURE
  9857.         end
  9858.         
  9859.         if @in_partition=0 and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'drop' and LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='false'
  9860.         begin
  9861.             RAISERROR(21336, 10, -1, @column)
  9862.             GOTO FAILURE
  9863.         end
  9864.  
  9865.         SELECT @columns = columns, @filter_clause=subset_filterclause, @ins_conflict_proc=ins_conflict_proc, @conflict_table=conflict_table FROM sysmergearticles WHERE name = @article AND pubid = @pubid
  9866.         IF LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'add'
  9867.             begin
  9868.                 exec @retcode = sp_MSsetbit @bm = @columns OUTPUT, @coltoadd=@columnid, @toset=1
  9869.                 if @@ERROR<>0 or @retcode<>0 
  9870.                     GOTO FAILURE
  9871.                 update syscolumns set colstat=colstat | @mergepublish where id=@objid and colid=@colid
  9872.                 if @@ERROR<>0
  9873.                     goto FAILURE
  9874.             end
  9875.         ELSE
  9876.             begin
  9877.                 
  9878.                 exec @retcode = sp_MSsetbit @bm = @columns OUTPUT, @coltoadd=@columnid, @toset=0
  9879.                 if @@ERROR<>0 or @retcode<>0 
  9880.                     GOTO FAILURE
  9881.                 if @columns = 0x00
  9882.                     begin
  9883.                         raiserror(21345, 16, -1)
  9884.                         goto FAILURE
  9885.                     end
  9886.                 exec @retcode = sp_MSclearcolumnbit @pubid, @artid, @column
  9887.                 if @@ERROR<>0 or @retcode<>0
  9888.                     goto FAILURE
  9889.             end
  9890.  
  9891.         /*
  9892.         ** Set vertical_partitioning flag so that publication view would be re-generated even
  9893.         ** if there is not subsetfilters nor join filters
  9894.         */
  9895.         UPDATE sysmergearticles  SET columns = @columns, vertical_partition=1 
  9896.             WHERE name = @article AND pubid = @pubid
  9897.         IF @@ERROR <> 0
  9898.         BEGIN
  9899.             RAISERROR (14021, 16, -1)
  9900.             GOTO FAILURE
  9901.         END
  9902.  
  9903.         select @column_list = NULL
  9904.         
  9905.         /*
  9906.         ** check to see if that column can be dropped based on current article's filter clause
  9907.         ** and if the article is involved in any join_filter_clauses - to make sure the drop of
  9908.         ** one column does not cripple any such joins
  9909.         */ 
  9910.         if ((@filter_clause is not NULL and @filter_clause <>'' ) or 
  9911.             exists (select * from sysmergesubsetfilters where pubid=@pubid and 
  9912.             (artid=@artid or join_articlename=@article))) and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
  9913.         begin
  9914.             exec @retcode = sp_MSgetcolumnlist @pubid, @column_list OUTPUT, @objid
  9915.             if @@ERROR<>0 or @retcode<>0
  9916.                 GOTO FAILURE
  9917.             select @object_view='TEMP_VIEW_' + @source_object  --@source_object is not quoted
  9918.             select @qual_object_view=quotename(@object_view)
  9919.  
  9920.             exec @retcode = sp_MSget_qualified_name @objid, @qual_source_object OUTPUT
  9921.             if @@ERROR<>0 or @retcode<>0
  9922.                 goto FAILURE
  9923.             select @quoted_source_object=QUOTENAME(@source_object)
  9924.             
  9925.             exec ('create view ' + @qual_object_view + ' as select ' + @column_list + ' from ' + @qual_source_object)
  9926.             if @@ERROR<>0
  9927.                 GOTO FAILURE
  9928.             if @filter_clause is not NULL and @filter_clause <>'' 
  9929.             begin
  9930.                 exec ('declare @test int select @test=1 from ' + @qual_object_view + ' ' + @quoted_source_object + ' where ' + @filter_clause)
  9931.                 if @@ERROR<>0
  9932.                     begin
  9933.                         exec('drop view ' + @qual_object_view)
  9934.                         raiserror(21256, 16, -1, @filter_clause, @source_object)
  9935.                         GOTO FAILURE
  9936.                     end
  9937.             end            
  9938.         end
  9939.         
  9940.         /*
  9941.         ** Check to make sure dropping a column will not breaking any other articles that using current article as join_article
  9942.         */
  9943.         if exists (select * from sysmergesubsetfilters where pubid=@pubid and 
  9944.             (artid=@artid or join_articlename=@article)) and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
  9945.         begin
  9946.             declare @join_articlename sysname
  9947.             declare per_article CURSOR LOCAL FAST_FORWARD FOR 
  9948.                 select artid, join_filterclause, join_articlename from sysmergesubsetfilters 
  9949.                     where pubid=@pubid and (join_articlename=@article or artid=@artid)
  9950.             for READ ONLY
  9951.             open per_article
  9952.             fetch per_article into @tmp_artid, @filter_clause, @join_articlename
  9953.             while (@@fetch_status<>-1)
  9954.             begin
  9955.                 if @artid<>@tmp_artid
  9956.                     select @tmp_object=object_name(objid) from sysmergearticles where pubid=@pubid and artid=@tmp_artid
  9957.                 else
  9958.                     select @tmp_object=object_name(objid) from sysmergearticles where pubid=@pubid and name=@join_articlename
  9959.                 select @qual_tmp_object=QUOTENAME(@tmp_object)
  9960.                 if @tmp_object is not NULl and @tmp_object<>''
  9961.                     begin
  9962.                         exec ('declare @test int select @test=1 from ' + @qual_object_view + ' ' + @quoted_source_object + ', ' + @qual_tmp_object + ' where ' + @filter_clause)                    
  9963.                         if @@ERROR<>0
  9964.                         begin
  9965.                             close per_article
  9966.                             deallocate per_article
  9967.                             raiserror(21256, 16, -1, @filter_clause, @source_object)
  9968.                             GOTO FAILURE
  9969.                         end
  9970.                     end
  9971.                 fetch per_article into @tmp_artid, @filter_clause, @join_articlename    
  9972.             end
  9973.             close per_article
  9974.             deallocate per_article        
  9975.         end            
  9976.     END   
  9977.  
  9978.     /*
  9979.     ** if snapshot is ready, change it to obsolete to force another snapshot run.    
  9980.     ** Note this is the third value of snapshot_ready. 0 for not ready, 1 for OK, 2 for obsolete
  9981.     */   
  9982.     IF EXISTS (SELECT * FROM sysmergepublications WHERE pubid=@pubid and snapshot_ready>0) 
  9983.             and LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='false'
  9984.         BEGIN
  9985.             update sysmergearticles set status=1, conflict_table=NULL where pubid=@pubid and artid=@artid and status<>5 and status <>6
  9986.             if @@ERROR<>0
  9987.                 goto FAILURE
  9988.         /*
  9989.         ** Force a re-generation of conflict table and its ins_proc
  9990.         */
  9991.             if object_id(@ins_conflict_proc) is not NULL
  9992.                 begin
  9993.                     set @quoted_source_object= quotename(@ins_conflict_proc)
  9994.                     exec ('drop proc ' + @quoted_source_object)
  9995.                     if @@ERROR<>0
  9996.                         goto FAILURE
  9997.                 end
  9998.             if object_id(@conflict_table) is not NULL
  9999.                 begin
  10000.                     set @quoted_source_object= quotename(@conflict_table)
  10001.                     exec ('drop table ' + @quoted_source_object)
  10002.                     if @@ERROR<>0
  10003.                         goto FAILURE
  10004.                 end
  10005.             /*
  10006.             ** make sure we know we really want to do this.
  10007.             */
  10008.             if @force_invalidate_snapshot = 0
  10009.                 begin
  10010.                     raiserror(20607, 16, -1)
  10011.                     goto FAILURE
  10012.                 end
  10013.             update sysmergepublications set snapshot_ready=2 where pubid=@pubid
  10014.             if @@ERROR<>0
  10015.                 goto FAILURE
  10016.  
  10017.             if @force_reinit_subscription = 0 and @status_value<>5 --5 is the value for new_inactive
  10018.                 begin
  10019.                     raiserror(20608, 16, -1)
  10020.                     goto FAILURE
  10021.                 end
  10022.  
  10023.             --do a global re
  10024.             
  10025.             if @force_reinit_subscription = 1
  10026.                 begin
  10027.                     --global reinitialization will bump up backward-comp-level to SP2.
  10028.                 exec @retcode = sp_MSreinitmergepublication @publication
  10029.                 if @retcode<>0 or @@ERROR<>0
  10030.                     goto FAILURE
  10031.                 end
  10032.             /*
  10033.             ** Even for vertical partitioning on new article - we do not need to bumpup backward-comp-level
  10034.             **
  10035.             else
  10036.                 begin    --bump up the backward-comp-level so that only 80 subscribers can use it.
  10037.                 exec @retcode = sp_MSBumpupCompLevel @pubid, 40
  10038.                 if @@ERROR<>0 or @retcode<>0
  10039.                     GOTO FAILURE
  10040.                 end
  10041.             */
  10042.         END
  10043.  
  10044.     COMMIT TRANSACTION
  10045.     if exists (select * from sysobjects where id = object_id(@qual_object_view))
  10046.         begin
  10047.             exec ('drop view ' + @qual_object_view)
  10048.         end
  10049.     return (0)
  10050. FAILURE:
  10051.  
  10052.     if @@TRANCOUNT >0 
  10053.         begin
  10054.             ROLLBACK TRANSACTION articlecolumn
  10055.             COMMIT TRAN
  10056.         end
  10057.  
  10058.     if exists (select * from sysobjects where id = object_id(@qual_object_view))
  10059.         begin
  10060.             exec ('drop view ' + @qual_object_view)
  10061.         end
  10062.  
  10063.     return (1)
  10064. go
  10065.  
  10066. EXEC dbo.sp_MS_marksystemobject sp_mergearticlecolumn
  10067. GO
  10068. grant execute on dbo.sp_mergearticlecolumn to public
  10069. go
  10070.  
  10071. raiserror('Creating procedure sp_helpmergearticlecolumn', 0, 1)
  10072. GO
  10073.  
  10074. CREATE PROCEDURE sp_helpmergearticlecolumn (
  10075.     @publication sysname,            /* The publication name */
  10076.     @article    sysname              /* The article name */
  10077.     ) AS
  10078.     SET NOCOUNT ON
  10079.  
  10080.     /*
  10081.     ** Declarations.
  10082.     */
  10083.     declare @colid        int
  10084.     declare @colmax        int
  10085.     declare @colname    sysname
  10086.     declare @published    bit
  10087.     declare @columns     binary(128)
  10088.     declare @pubid         uniqueidentifier
  10089.     declare @retcode     int
  10090.     declare @objid        int
  10091.     declare @publisher    sysname
  10092.     declare @publisher_db    sysname
  10093.  
  10094.     select @publisher = @@SERVERNAME
  10095.     select @publisher_db = db_name()
  10096.  
  10097.     /*
  10098.     ** Parameter Check: @publication.
  10099.     ** The @publication name must conform to the rules for identifiers.
  10100.     */
  10101.     IF @publication IS NULL
  10102.     BEGIN
  10103.         RAISERROR (14043, 16, -1, '@publication')
  10104.         RETURN (1)
  10105.     END
  10106.  
  10107.     EXECUTE @retcode = dbo.sp_validname @publication
  10108.     IF @retcode <> 0 or @@ERROR<>0
  10109.         RETURN (1)
  10110.     
  10111.     SELECT @pubid = pubid FROM sysmergepublications WHERE name = @publication 
  10112.                                                           and LOWER(publisher)=LOWER(@publisher)
  10113.                                                           and publisher_db = @publisher_db
  10114.     IF @pubid IS NULL
  10115.     BEGIN
  10116.         RAISERROR (20026, 11, -1, @publication)
  10117.         RETURN (1)
  10118.     END
  10119.  
  10120.     -- Security check. (Done after @pubid retrieval, because this param is needed here.)
  10121.     if  1 <> {fn ISPALUSER(@pubid)} and
  10122.         (1 <> is_member('replmonitor') or is_member('replmonitor') is null) 
  10123.     begin
  10124.         raiserror(15247,-1,-1)
  10125.         return 1
  10126.     end
  10127.  
  10128.     /*
  10129.     ** Parameter Check: @article.
  10130.     ** The @article name must conform to the rules for identifiers.
  10131.     */
  10132.  
  10133.     IF @article IS NULL
  10134.         BEGIN
  10135.             RAISERROR (14043, 16, -1, '@article')
  10136.             RETURN (1)
  10137.         END
  10138.     EXECUTE @retcode = dbo.sp_validname @article
  10139.     IF @retcode <> 0 or @@ERROR<>0
  10140.         RETURN (1)
  10141.  
  10142.     /*
  10143.     ** Parameter Check:  @article, @publication.
  10144.     ** Check to make sure that the article exists in this publication.
  10145.     */
  10146.  
  10147.     IF NOT EXISTS (SELECT * FROM sysmergearticles WHERE pubid = @pubid AND name = @article)
  10148.         BEGIN
  10149.             RAISERROR (20027, 11, -1, @article)
  10150.             RETURN (1)
  10151.         END
  10152.  
  10153.     SELECT @columns = columns, @objid=objid FROM sysmergearticles
  10154.         WHERE name = @article AND pubid = @pubid
  10155.  
  10156.     create table #tmp (column_id int, column_name sysname collate database_default, published bit)
  10157.     select TOP 1 @colid = colid from syscolumns where id = @objid order by colid ASC
  10158.     select TOP 1 @colmax = colid from syscolumns where id = @objid order by colid DESC
  10159.     while (@colid <= @colmax)
  10160.     begin
  10161.     if exists (select * from syscolumns where id = @objid and colid = @colid)
  10162.         begin
  10163.             select @colname = name from syscolumns where id=@objid and colid=@colid
  10164.             exec @retcode = sp_MStestbit @bm=@columns, @coltotest=@colid
  10165.             if @retcode<>0
  10166.                 select @published=1
  10167.             else
  10168.                 select @published=0
  10169.             insert into #tmp values(@colid, @colname, @published)
  10170.         end
  10171.         select @colid=@colid + 1
  10172.     end
  10173.     select * from #tmp
  10174.     drop table #tmp
  10175.     go
  10176.  
  10177. EXEC dbo.sp_MS_marksystemobject sp_helpmergearticlecolumn
  10178. GO
  10179. grant execute on dbo.sp_helpmergearticlecolumn to public
  10180. go
  10181.         
  10182. raiserror('Creating procedure sp_MSreinitmergepublication', 0, 1)
  10183. GO
  10184.  
  10185. create procedure sp_MSreinitmergepublication
  10186.     @publication    sysname,
  10187.     @upload_first    bit = 0
  10188. AS
  10189.     declare @pubid                uniqueidentifier
  10190.     declare @schematext         nvarchar(4000)
  10191.     declare @schemaversion         int
  10192.     declare @schemaguid            uniqueidentifier
  10193.     declare @schematype            int
  10194.     declare @publisher            sysname
  10195.     declare @retcode            int
  10196.     declare @publisher_db        sysname
  10197.  
  10198.     set nocount on
  10199.         
  10200.     select @publisher=@@servername
  10201.     select @publisher_db = db_name()
  10202.     
  10203.     select @pubid=pubid from sysmergepublications 
  10204.         where name=@publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  10205.  
  10206.     raiserror(21353,10, -1,@publication)
  10207.     exec @retcode=sp_MSBumpupCompLevel @pubid, 30 --for 7.0 SP2, which has limited support for this
  10208.     if @@ERROR<>0 or @retcode<>0        
  10209.         return (1)
  10210.     select @schematext = 'exec sp_MSreinit_hub '+ QUOTENAME(@publisher) + ', ' + QUOTENAME(@publisher_db) + ', ' + QUOTENAME(@publication) + ', ' + convert(nvarchar, @upload_first)
  10211.     select @schemaversion = schemaversion from sysmergeschemachange
  10212.     if (@schemaversion is NULL)
  10213.         set @schemaversion = 1
  10214.     else
  10215.         select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange        
  10216.     set @schemaguid = newid()
  10217.     if @upload_first = 0
  10218.         set @schematype = 12 /* reinit_all */
  10219.     else
  10220.         set @schematype = 14 /* reinit_with_upload*/
  10221.     exec @retcode=sp_MSinsertschemachange @pubid, @schemaguid, @schemaversion, @schemaguid, @schematype, @schematext
  10222.     if @@ERROR<>0 or @retcode<>0 
  10223.         return (1)
  10224.         
  10225.     update MSmerge_replinfo set schemaversion=0, recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL
  10226.         where repid in (select subid from sysmergesubscriptions where subid<>pubid and pubid=@pubid and subscription_type=0)
  10227.     if @@ERROR<>0 
  10228.         return (1)
  10229.  
  10230.     -- set all article status to inactive as a starting point - which sort or cleanup the newly added status
  10231.     -- 5 and 6.
  10232.  
  10233.     if @upload_first=0 --do not reset status is upload_first is true. Otherwise, 
  10234.                        --creating triggers would fail.    
  10235.     begin
  10236.         update sysmergearticles set status=1 where pubid=@pubid 
  10237.         if @@ERROR<>0
  10238.             return (1)
  10239.     end
  10240.     update MSmerge_replinfo set schemaversion=-1, recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL
  10241.         where repid in (select subid from sysmergesubscriptions where subid<>pubid and pubid=@pubid and subscription_type>0)
  10242.         
  10243.     if @@ERROR<>0 
  10244.         return (1)
  10245.  
  10246. GO
  10247. exec dbo.sp_MS_marksystemobject sp_MSreinitmergepublication
  10248. go  
  10249.  
  10250.  
  10251. raiserror('Creating procedure sp_MSreinit_hub', 0, 1)
  10252. GO
  10253. create procedure sp_MSreinit_hub
  10254.     @publisher        sysname,
  10255.     @publisher_db    sysname,
  10256.     @publication    sysname,
  10257.     @upload_first    bit
  10258. AS
  10259.     declare @retcode            int
  10260.     declare @pubid                uniqueidentifier
  10261.     declare @hub_pubname        sysname
  10262.     declare @hub_publisher        sysname
  10263.     declare @hub_publisher_db    sysname
  10264.     declare @hub_pubid            uniqueidentifier
  10265.     declare @schematext         nvarchar(4000)
  10266.     declare @schemaversion         int
  10267.     declare @schemaguid            uniqueidentifier
  10268.     declare @schematype            int
  10269.  
  10270.     /* 
  10271.     ** Security Check.
  10272.     ** We use login_name stored in syssubscriptions to manage security 
  10273.     */
  10274.     exec @retcode= dbo.sp_MSreplcheck_subscribe
  10275.     if @@ERROR <> 0 or @retcode <> 0
  10276.         return(1)
  10277.     
  10278.     select @pubid=pubid from sysmergepublications 
  10279.         where name=@publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
  10280.     BEGIN TRAN
  10281.     SAVE TRAN reinithub
  10282.     
  10283.     /* Find all publications that are being republished at the subscriber */
  10284.     declare reinit_hub CURSOR LOCAL FAST_FORWARD FOR select DISTINCT p.pubid, p.name, p.publisher, p.publisher_db FROM sysmergepublications p
  10285.         where UPPER(p.publisher)=UPPER(@@SERVERNAME) and p.publisher_db=db_name()
  10286.             and exists (select * from sysmergearticles where (objid in 
  10287.                     (select objid from sysmergearticles where pubid=@pubid)) and (objid in 
  10288.                     (select objid from sysmergearticles where pubid=p.pubid))) and p.pubid<>@pubid
  10289.     FOR READ ONLY
  10290.     open reinit_hub
  10291.     fetch reinit_hub into @hub_pubid, @hub_pubname, @hub_publisher, @hub_publisher_db
  10292.     while (@@fetch_status<>-1)
  10293.     begin
  10294.         if @upload_first=1
  10295.         begin
  10296.             update sysmergesubscriptions set status=5 where pubid=@hub_pubid
  10297.             if @@ERROR<>0
  10298.                 goto FAILURE
  10299.         end
  10300.         select @schematext = 'exec sp_MSreinit_hub '+ QUOTENAME(@hub_publisher) + ', ' + QUOTENAME(@hub_publisher_db) + ', ' + QUOTENAME(@hub_pubname) + ', ' + convert(nvarchar, @upload_first)
  10301.         select @schemaversion = schemaversion from sysmergeschemachange
  10302.         if (@schemaversion is NULL)
  10303.             set @schemaversion = 1
  10304.         else
  10305.             select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange        
  10306.         set @schemaguid = newid()
  10307.         if @upload_first=0
  10308.             set @schematype = 12 /* reinit_all */
  10309.         else
  10310.             set @schematype = 14 /*reinitwithupload */
  10311.         exec @retcode=sp_MSinsertschemachange @hub_pubid, @schemaguid, @schemaversion, @schemaguid, @schematype, @schematext
  10312.         if @@ERROR<>0 or @retcode<>0
  10313.         begin
  10314.             select @retcode = 1
  10315.             GOTO FAILURE
  10316.         end
  10317.         raiserror(21354, 10, -1, @hub_pubname)
  10318.         exec @retcode=sp_MSBumpupCompLevel @hub_pubid, 40 
  10319.         if @@ERROR<>0 or @retcode<>0        
  10320.             GOTO FAILURE
  10321.  
  10322.         update sysmergepublications set snapshot_ready=2 where pubid=@hub_pubid
  10323.         if @@ERROR<>0
  10324.             goto FAILURE
  10325.         fetch next from reinit_hub into @hub_pubid, @hub_pubname, @hub_publisher, @hub_publisher_db
  10326.     end
  10327.     close reinit_hub
  10328.     deallocate reinit_hub
  10329.     COMMIT TRAN
  10330.     return (0)
  10331. FAILURE:
  10332.     close reinit_hub
  10333.     deallocate reinit_hub
  10334.     raiserror('Error occurred when applying reinit-all command at subscribers', 16, -1)
  10335.     if @@TRANCOUNT >0 
  10336.     begin
  10337.         ROLLBACK TRANSACTION reinithub
  10338.         COMMIT TRAN
  10339.     end
  10340.     return (0)
  10341. GO
  10342.  
  10343. exec dbo.sp_MS_marksystemobject sp_MSreinit_hub
  10344. go  
  10345.  
  10346. grant execute on dbo.sp_MSreinit_hub to public
  10347. go
  10348.  
  10349. raiserror('Creating procedure sp_reinitmergesubscription', 0, 1)
  10350. GO
  10351.  
  10352. create procedure sp_reinitmergesubscription
  10353.     @publication    sysname  = 'all',
  10354.     @subscriber     sysname  = 'all',
  10355.     @subscriber_db  sysname  = 'all',
  10356.     @upload_first    nvarchar(5) = 'FALSE'
  10357. AS
  10358.     declare @pubid                  uniqueidentifier
  10359.     declare @subid                  uniqueidentifier
  10360.     declare @subscription_type        int
  10361.     declare @reinit_bit                int
  10362.     declare @publisher                sysname
  10363.     declare @publisher_db            sysname
  10364.     declare @distribdb                sysname
  10365.     declare @distributor            sysname
  10366.     declare @distproc                nvarchar(300)
  10367.     declare @retcode                int
  10368.     declare @uploadbit                bit
  10369.     declare    @pubname                sysname
  10370.     declare @subsrvid                int
  10371.     declare @subdb                    sysname 
  10372.     declare @subname                sysname
  10373.     /* 
  10374.     ** Security Check.
  10375.     ** We use login_name stored in syssubscriptions to manage security 
  10376.     */
  10377.     exec @retcode = dbo.sp_MSreplcheck_publish
  10378.     if @@ERROR <> 0 or @retcode <> 0
  10379.         return(1)
  10380.  
  10381.     set nocount on
  10382.     /*
  10383.     ** Replace 'all' with '%'
  10384.     */
  10385.  
  10386.     /* make sure current database is enabled for merge replication */
  10387.     exec @retcode=dbo.sp_MSCheckmergereplication
  10388.     if @@ERROR<>0 or @retcode<>0
  10389.         return (1)
  10390.  
  10391.     if LOWER(@publication) = 'all'
  10392.         SELECT @publication = '%'
  10393.  
  10394.     if LOWER(@subscriber) = 'all'
  10395.         SELECT @subscriber = '%'
  10396.  
  10397.     if LOWER(@subscriber_db) = 'all'
  10398.         SELECT @subscriber_db = '%'
  10399.  
  10400.     select @publisher = @@SERVERNAME
  10401.     select @publisher_db=db_name()
  10402.     
  10403.     /*
  10404.     ** At publisher side, publication name is unique
  10405.     */
  10406.     IF NOT EXISTS (SELECT * FROM sysmergepublications 
  10407.         WHERE name LIKE @publication)
  10408.         BEGIN
  10409.         IF @publication = '%'
  10410.                 RAISERROR (14008, 11, -1)
  10411.         ELSE
  10412.                 RAISERROR (20026, 11, -1, @publication)
  10413.         RETURN (1)
  10414.         END
  10415.  
  10416.     /* if snapshot has not been ran yet, there is no point doing reinitialization */
  10417.     if not exists (select * from sysmergepublications where name like @publication and snapshot_ready>0)
  10418.         return (0)
  10419.         
  10420.     if LOWER(@upload_first collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  10421.         select @uploadbit  = 1
  10422.     else
  10423.         select @uploadbit  = 0
  10424.  
  10425.     EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb   = @distribdb OUTPUT
  10426.         IF @@ERROR <> 0 or @retcode <> 0
  10427.                 return (1)
  10428.  
  10429.     SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSrefresh_anonymous '
  10430.  
  10431.     if @subscriber = '%' and @subscriber_db = '%'
  10432.     begin
  10433.         exec @retcode = @distproc @publication, @publisher, @publisher_db 
  10434.         if @@ERROR<>0 or @retcode<>0
  10435.                 return (1)
  10436.                 
  10437.         declare reinit_all CURSOR LOCAL FAST_FORWARD FOR 
  10438.             select name from sysmergepublications where LOWER(publisher)=LOWER(@@SERVERNAME) and 
  10439.                 publisher_db=db_name() and snapshot_ready>0 and name like @publication
  10440.         For READ only
  10441.         open reinit_all
  10442.         fetch reinit_all into @pubname
  10443.         while (@@fetch_status<>-1)
  10444.         begin
  10445.             exec @retcode = sp_MSreinitmergepublication @pubname, @uploadbit
  10446.             if @@ERROR<>0 or @retcode<>0
  10447.             begin
  10448.                 close reinit_all
  10449.                 deallocate reinit_all
  10450.                 return (1)
  10451.             end
  10452.             
  10453.             fetch next from reinit_all into @pubname
  10454.         end
  10455.         close reinit_all
  10456.         deallocate reinit_all
  10457.     end
  10458.  
  10459.     SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSmarkreinit '
  10460.  
  10461.     BEGIN TRAN
  10462.     SAVE TRAN reinitsubscription
  10463.     
  10464.     Declare SYN_CUR CURSOR LOCAL FAST_FORWARD FOR 
  10465.         select subs.subid, subs.subscription_type, pubs.publisher, pubs.publisher_db, pubs.name, 
  10466.                 subs.srvid, subs.db_name
  10467.             from sysmergepublications pubs, sysmergesubscriptions subs
  10468.                 where pubs.name LIKE  @publication 
  10469.                      and UPPER(pubs.publisher)=UPPER(@@servername) 
  10470.                      and pubs.publisher_db=db_name()
  10471.                     AND pubs.pubid=subs.pubid
  10472.                     AND subs.pubid<>subs.subid
  10473.                     AND subs.status <>0 --for unsynced subscription, there is no need to reinit.
  10474.                     AND ((@subscriber_db = N'%') or (db_name = @subscriber_db))
  10475.                     AND srvid in (select srvid from master..sysservers where ((@subscriber = N'%') or (UPPER(srvname) = UPPER(@subscriber) collate database_default)))
  10476.     FOR READ ONLY
  10477.     open SYN_CUR
  10478.     fetch SYN_CUR into @subid, @subscription_type, @publisher, @publisher_db, @pubname, @subsrvid, @subdb
  10479.     while (@@fetch_status<>-1)
  10480.     BEGIN  
  10481.     -- Security check 
  10482.         if not exists (select * from sysmergesubscriptions subs1 where
  10483.         (suser_sname(suser_sid()) = subs1.login_name OR 
  10484.         is_member('db_owner')=1 OR 
  10485.         is_srvrolemember('sysadmin') = 1) and
  10486.         subid = @subid)
  10487.         continue        
  10488.  
  10489.         select @subname = srvname from master..sysservers where srvid = @subsrvid
  10490.     
  10491.             if @subscription_type = 0 
  10492.                  update MSmerge_replinfo set schemaversion=0, recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL
  10493.                       where repid=@subid and schemaversion is NOT NULL
  10494.             else
  10495.                     update MSmerge_replinfo set schemaversion= -1, recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL
  10496.                        where repid=@subid and schemaversion is NOT NULL
  10497.         
  10498.         if @@rowcount <> 0 and @uploadbit = 1
  10499.         begin
  10500.             update sysmergesubscriptions set status = 5 where subid=@subid
  10501.             if @@ERROR<>0
  10502.                 goto Failure
  10503.         end
  10504.  
  10505.         -- If subscriber was preventing us from cleaning up metadata, set the status
  10506.         update sysmergesubscriptions set status = 8 where subid = @subid and status = 7
  10507.         if @@rowcount <> 0
  10508.             exec sp_MSquiescecheck
  10509.             
  10510.         -- 0 for push and -1 for pull
  10511.         exec @distproc @publisher, @publisher_db, @pubname, @subname, @subdb, 1
  10512.         if @@ERROR<>0
  10513.         BEGIN
  10514.             goto Failure
  10515.         END            
  10516.         fetch next from SYN_CUR into @subid, @subscription_type, @publisher, 
  10517.             @publisher_db, @pubname, @subsrvid, @subdb        
  10518.     END
  10519.     close SYN_CUR
  10520.     deallocate SYN_CUR
  10521.     commit TRAN
  10522.     return (0)
  10523. Failure:
  10524.     close SYN_CUR
  10525.     deallocate SYN_CUR
  10526.     if @@TRANCOUNT > 0
  10527.     begin
  10528.         ROLLBACK TRANSACTION reinitsubscription
  10529.         COMMIT TRANSACTION
  10530.     end
  10531.     return (1)
  10532.  
  10533. GO
  10534.  
  10535. exec dbo.sp_MS_marksystemobject sp_reinitmergesubscription
  10536. go  
  10537.  
  10538. grant execute on dbo.sp_reinitmergesubscription to public
  10539. go
  10540.  
  10541. raiserror('Creating procedure sp_MSpublicationview', 0,1)
  10542. GO
  10543. CREATE PROCEDURE sp_MSpublicationview(
  10544.     @publication sysname,
  10545.     @force_flag int = 0,
  10546.     @max_network_optimization bit = 0
  10547.     ) AS
  10548.  
  10549.     declare     @pubid              uniqueidentifier
  10550.     declare     @artid              uniqueidentifier
  10551.     declare     @join_articlename       nvarchar(270)
  10552.     declare     @join_viewname      nvarchar(270)
  10553.     declare     @join_before_view      nvarchar(270)
  10554.     declare        @before_name        nvarchar(270)
  10555.     declare        @before_viewname    nvarchar(270)
  10556.     declare     @unqual_sourcename    nvarchar(270)
  10557.     declare     @article            nvarchar(270)
  10558.     declare     @art_nick           int
  10559.     declare     @join_nick          int
  10560.     declare     @join_filterclause  nvarchar(4000)
  10561.     declare     @bool_filterclause  nvarchar(4000)
  10562.     declare     @view_rule          nvarchar(4000)
  10563.     declare        @before_view_rule    nvarchar(4000)
  10564.     declare        @before_objid        int
  10565.     declare     @article_level      int
  10566.     declare     @progress           int
  10567.     declare     @art                int
  10568.     declare     @viewname           nvarchar(270)
  10569.     declare     @procname           nvarchar(300)
  10570.     declare     @source_objid       int
  10571.     declare     @source_object      nvarchar(270)
  10572.     declare     @sync_objid         int
  10573.     declare     @bitset                int
  10574.     declare     @permanent          int
  10575.     declare     @temporary          int
  10576.     declare     @filter_id          int
  10577.     declare     @filter_id_str      nvarchar(10)
  10578.     declare     @guidstr nvarchar(40)
  10579.     declare     @pubidstr nvarchar(40)
  10580.     declare     @rgcol              nvarchar(270)
  10581.     declare     @view_type          int
  10582.     declare     @belongsname        nvarchar(270)
  10583.     declare     @join_nickstr       nvarchar(10)
  10584.     declare     @unqual_jointable   nvarchar(270)  
  10585.     declare     @hasguid            int
  10586.     declare     @vertical_partition int
  10587.     declare     @join_unique_key    int
  10588.     declare     @simple_join_view   int
  10589.     declare     @join_filterid      int
  10590.     declare     @allhaveguids       int
  10591.     declare     @command            nvarchar(4000)
  10592.     declare     @objid              int
  10593.     declare     @owner              nvarchar(270)
  10594.     declare        @table                nvarchar(270)
  10595.     declare     @quoted_obj         nvarchar(290)
  10596.     declare     @quoted_rowguid     nvarchar(290)
  10597.     declare     @before_rowguidname    sysname
  10598.     declare     @snapshot_ready        int
  10599.     declare     @columns            varbinary(128)
  10600.     declare        @column_list        nvarchar(4000)
  10601.     declare        @prefixed_column_list        nvarchar(4000)
  10602.     declare     @colname            nvarchar(270)
  10603.     declare     @colid                int
  10604.     declare     @dynamic_filters    bit
  10605.     declare        @alias_for_sourceobject    sysname
  10606.     declare        @retcode            int
  10607.     declare     @dbname             sysname
  10608.     declare        @allcolsreturned    bit
  10609.     declare        @tempcollistphase    int
  10610.     declare        @viewexeccmd        nvarchar(200)
  10611.     declare        @beforeviewexeccmd    nvarchar(200)
  10612.     
  10613.     -- Security check
  10614.     exec @retcode= dbo.sp_MSreplcheck_publish
  10615.     if @@error <> 0 or @retcode <> 0 return (1)
  10616.  
  10617.     set @tempcollistphase= 100
  10618.     set @viewexeccmd= 'select cmdtext from #viewcmd where phase<>' 
  10619.                         + cast(@tempcollistphase as nvarchar(5)) 
  10620.                         + ' order by phase,step'
  10621.     set @beforeviewexeccmd= 'select cmdtext from #beforeviewcmd order by phase,step'
  10622.  
  10623.     set @progress       = 1
  10624.     set @article_level  = 0
  10625.     set @permanent      = 1
  10626.     set @temporary      = 2
  10627.     set @allhaveguids   = 1
  10628.     set @before_rowguidname = NULL
  10629.  
  10630.     /*
  10631.     ** Only legal publisher can run this stored procedure
  10632.     */
  10633.     set nocount on
  10634.     /* make sure current database is enabled for merge replication */
  10635.     exec @retcode=dbo.sp_MSCheckmergereplication
  10636.     if @@ERROR<>0 or @retcode<>0
  10637.         return (1)
  10638.  
  10639.     set @dbname= db_name()
  10640.  
  10641.     select @pubid = pubid, @snapshot_ready = snapshot_ready, @dynamic_filters = dynamic_filters FROM sysmergepublications 
  10642.         WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() 
  10643.     IF @pubid IS NULL
  10644.     BEGIN
  10645.         RAISERROR (20026, 11, -1, @publication)
  10646.         RETURN (1)
  10647.     END
  10648.  
  10649.     select @table=object_name(objid) from sysmergearticles where pubid=@pubid and (columns is NULL or columns = 0x00)
  10650.     if @table is not NULL
  10651.     begin
  10652.         raiserror(21318, 16, -1, @table)
  10653.         return (1)
  10654.     end
  10655.  
  10656.     -- If snapshot is already ready, views are good.  Don't drop and recreate as someone
  10657.     -- might be using them.
  10658.     
  10659.     if @snapshot_ready = 1 and @force_flag = 0
  10660.         return (0)
  10661.         
  10662.     exec @retcode = dbo.sp_MSguidtostr @pubid, @pubidstr out
  10663.     if @@ERROR <>0 OR @retcode <>0 return (1)
  10664.  
  10665.     create table #viewcmd (phase int, step int identity(1,1), cmdtext nvarchar(4000))
  10666.     if @@error<>0 goto FAILURE
  10667.     create table #beforeviewcmd (phase int, step int identity(1,1), cmdtext nvarchar(4000))
  10668.     if @@error<>0 goto FAILURE
  10669.  
  10670.     create table #art(indexcol int identity NOT NULL, art_nick int NOT NULL, article_level int NOT NULL)
  10671.     if @@ERROR <> 0
  10672.     begin
  10673.         goto FAILURE
  10674.     end
  10675.  
  10676.     while @progress > 0
  10677.     BEGIN
  10678.         /*
  10679.         ** Select articles that have either a boolean_filter or at least one join filter 
  10680.         ** into a temp table in an optimized order.
  10681.         */
  10682.         insert into #art(art_nick, article_level) select nickname, @article_level from sysmergearticles 
  10683.             where pubid=@pubid and nickname not in (select art_nick from #art)
  10684.                 and nickname not in 
  10685.                 (select  art_nickname from sysmergesubsetfilters
  10686.                     where pubid=@pubid and join_nickname not in 
  10687.                         (select art_nick from #art))
  10688.         /*
  10689.         ** NOTENOTE: add error checking here.
  10690.         */
  10691.  
  10692.         set @progress = @@rowcount
  10693.         select @article_level = @article_level + 1
  10694.     END
  10695.  
  10696.     /* Drop the old views and reset sync_objid */
  10697.     select @art_nick = min(nickname) from sysmergearticles where pubid = @pubid and objid<>sync_objid
  10698.     while @art_nick is not null
  10699.     begin
  10700.         /* Drop the old view */
  10701.         select @viewname = OBJECT_NAME (sync_objid), @before_viewname = OBJECT_NAME(before_view_objid)
  10702.             from sysmergearticles where
  10703.             pubid = @pubid and nickname = @art_nick
  10704.         if @viewname IS NOT NULL
  10705.         begin
  10706.             select @quoted_obj = QUOTENAME(@viewname)
  10707.             exec ('drop view ' + @quoted_obj)
  10708.         end
  10709.         if @before_viewname IS NOT NULL
  10710.         begin
  10711.             select @quoted_obj = QUOTENAME(@before_viewname)
  10712.             exec ('drop view ' + @quoted_obj)
  10713.         end
  10714.         /* Update the row in sysmergearticles */
  10715.         update sysmergearticles set view_type = 0, sync_objid = objid where 
  10716.             pubid = @pubid and nickname = @art_nick
  10717.         if @@ERROR <> 0 goto FAILURE
  10718.  
  10719.         /* Find the next one */
  10720.         select @art_nick = min(nickname) from sysmergearticles where pubid = @pubid and objid<>sync_objid
  10721.     end
  10722.         
  10723.     set @art = 0
  10724.     select @art=min(indexcol) from #art where indexcol>@art
  10725.  
  10726.     while (@art is not null)
  10727.     begin
  10728.         delete from #viewcmd
  10729.         delete from #beforeviewcmd
  10730.         
  10731.         select @art_nick=art_nick, @article_level = article_level from #art 
  10732.                 where indexcol = @art
  10733.         select @article = name, @artid = artid, @columns = columns, @source_objid = objid,
  10734.             @sync_objid = sync_objid, @procname = view_sel_proc, @before_objid = before_image_objid from sysmergearticles 
  10735.                 where nickname=@art_nick and pubid = @pubid
  10736.                 
  10737.         -- Need to run sp_MSgetcolumnlist already, to initialize @allcolsreturned.
  10738.         -- Just use an otherwise unused @phase value, which will be updated later on.
  10739.         insert into #viewcmd(phase, cmdtext) exec dbo.sp_MSgetcolumnlist 
  10740.                                                     @pubid=@pubid,
  10741.                                                     @column_list=@column_list output,
  10742.                                                     @source_objid=@source_objid,
  10743.                                                     @phase=@tempcollistphase,
  10744.                                                     @allcolsreturned=@allcolsreturned output
  10745.  
  10746.         set @before_name = OBJECT_NAME(@before_objid)
  10747.         if @before_name is not null
  10748.         begin
  10749.             select @before_rowguidname=name from syscolumns where id=@source_objid and columnproperty(@source_objid, name , 'isrowguidcol')=1
  10750.             exec @retcode = dbo.sp_MSguidtostr @pubid, @guidstr out
  10751.             set @before_viewname = @before_name + '_v_' + @guidstr
  10752.         end
  10753.         else
  10754.             set @before_viewname = NULL
  10755.         
  10756.         exec @retcode = dbo.sp_MSguidtostr @artid, @guidstr out
  10757.         if @@ERROR <>0 OR @retcode <>0 return (1)
  10758.  
  10759.         select @source_object = QUOTENAME(user_name(uid)) + '.' + QUOTENAME(name) from sysobjects 
  10760.                 where id = @source_objid 
  10761.         select @unqual_sourcename = QUOTENAME(OBJECT_NAME(@source_objid))
  10762.         
  10763.         select @bool_filterclause=subset_filterclause, @vertical_partition=vertical_partition 
  10764.             from sysmergearticles where name = @article and pubid = @pubid
  10765.  
  10766.         -- verify the syntax of boolean filter, if added with vertical-partition to true
  10767.         -- in this case, the filter clause can contain columns that do not exist in the partition.
  10768.         if len(@bool_filterclause) > 0
  10769.         begin
  10770.             /*
  10771.             -- let server return appropriate error message 
  10772.             exec ('select ' + @column_list + ' into #temptable_publicationview from ' + @source_object + 
  10773.                 'declare @test int select @test=1 from #temptable_publicationview ' + @unqual_sourcename + ' where ' + @bool_filterclause)
  10774.             if @@ERROR<>0
  10775.             begin
  10776.                 raiserror(21256, 16, -1, @bool_filterclause, @source_object)
  10777.                 return (1)
  10778.             end
  10779.             */
  10780.             select @bool_filterclause = ' (' + @bool_filterclause + ') '
  10781.         end
  10782.                 
  10783.         set @rgcol = NULL
  10784.         select @rgcol = QUOTENAME(name) from syscolumns where id = @source_objid and
  10785.                 ColumnProperty(id, name, 'isrowguidcol') = 1
  10786.         if @rgcol is not NULL
  10787.             set @hasguid = 1
  10788.         else 
  10789.         begin
  10790.             set @hasguid = 0
  10791.             set @allhaveguids = 0
  10792.         end
  10793.  
  10794.         /*
  10795.         ** Process non looping articles that have either a boolean or a join_filter.
  10796.         */
  10797.         if ( @article_level > 0 OR (len(@bool_filterclause) > 0) ) 
  10798.         begin
  10799.            /*
  10800.             ** If the article has a previously generated view, then drop the view before 
  10801.             ** creating the new one.
  10802.             */
  10803.             set @viewname = NULL
  10804.             select @viewname =  name from sysobjects where id = @sync_objid and
  10805.                 ObjectProperty (id, 'IsView') = 1  and
  10806.                 ObjectProperty (id, 'IsMSShipped') = 1 
  10807.             if @viewname IS NOT NULL
  10808.             begin
  10809.                 select @quoted_obj = QUOTENAME(@viewname)
  10810.                 exec ('drop view ' + @quoted_obj)
  10811.                 if @@ERROR<>0 return (1)
  10812.             end
  10813.                 /*
  10814.                 ** Any join filter(s)? If any, process join filter(s)
  10815.                 */
  10816.             if (@article_level > 0) 
  10817.             begin
  10818.                 declare pub1 CURSOR LOCAL FAST_FORWARD FOR select join_filterclause, join_nickname, join_articlename,
  10819.                     join_unique_key, join_filterid from sysmergesubsetfilters where pubid=@pubid and artid=@artid
  10820.                 FOR READ ONLY
  10821.                 open pub1                                       
  10822.                 fetch pub1 into @join_filterclause, @join_nick, @join_articlename, @join_unique_key, @join_filterid
  10823.                 select @join_filterclause=' ( ' + @join_filterclause + ') '
  10824.                 select @unqual_jointable = QUOTENAME(name) from sysobjects 
  10825.                     where id = (select objid from sysmergearticles where name=@join_articlename and pubid=@pubid) 
  10826.                 
  10827.                 if @max_network_optimization = 0
  10828.                     select @join_viewname = object_name(sync_objid), @join_before_view = object_name(before_image_objid)
  10829.                     from sysmergearticles where nickname = @join_nick and pubid = @pubid
  10830.                 else
  10831.                     select @join_viewname = object_name(sync_objid), 
  10832.                     @join_before_view = object_name(case when before_view_objid is not null then before_view_objid else before_image_objid end)
  10833.                     from sysmergearticles where nickname = @join_nick and pubid = @pubid
  10834.                     
  10835.                 select @join_viewname = QUOTENAME(@join_viewname)
  10836.  
  10837.                 if 1=@hasguid
  10838.                 begin
  10839.                     if (@join_unique_key = 1 and (@bool_filterclause is null or len(@bool_filterclause) = 0) and
  10840.                         not exists (select * from sysmergesubsetfilters where pubid=@pubid and artid=@artid and join_filterid <> @join_filterid))
  10841.                     begin
  10842.                         set @simple_join_view = 1
  10843.  
  10844.                         set @view_rule= 'select '
  10845.                         insert into #viewcmd(phase,cmdtext) values (3, @view_rule)
  10846.  
  10847.                         -- sp_MSgetcolumnlist was called at the beginning of the article loop.
  10848.                         -- Thus, we now just set the right phase.
  10849.                         update #viewcmd set phase= 4 where phase=@tempcollistphase
  10850.  
  10851.                         set @view_rule= ' from ' + @source_object + ' ' + @unqual_sourcename + ' , ' +  @join_viewname + ' ' + @unqual_jointable + ' where (' + @join_filterclause
  10852.                                         + ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'
  10853.                          insert into #viewcmd(phase,cmdtext) values (5, @view_rule)
  10854.                     end
  10855.                     else
  10856.                     begin
  10857.                         set @simple_join_view = 0
  10858.  
  10859.                         /* Alias the source object with the unqualified name and use that to select the rowguidcol */                   
  10860.                         set @view_rule = 'select ' + @unqual_sourcename + '.rowguidcol from ' + @source_object  + ' ' + @unqual_sourcename + ' , ' +  @join_viewname + ' ' + @unqual_jointable + ' where (' + @join_filterclause
  10861.                                         + ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'
  10862.                         insert into #viewcmd(phase, cmdtext) values(3, @view_rule)
  10863.                     end
  10864.                 end
  10865.  
  10866.                 if @before_name is not null
  10867.                 begin
  10868.                     set @before_view_rule = 'select * from ' + @before_name + ' ' +  @unqual_sourcename + ' where (exists (select * from ' +
  10869.                                                 @join_viewname + ' ' + @unqual_jointable + ' where ' + @join_filterclause + ') or exists (select * from ' +
  10870.                                                 @join_before_view + ' ' + @unqual_jointable + ' where ' + @join_filterclause + ') '
  10871.                     insert into #beforeviewcmd(phase, cmdtext) values(3, @before_view_rule)
  10872.                 end
  10873.                 
  10874.                 fetch next from pub1 into @join_filterclause, @join_nick, @join_articlename, @join_unique_key, @join_filterid
  10875.                 WHILE (@@fetch_status <> -1)
  10876.                 begin
  10877.                     select @join_filterclause=' ( ' + @join_filterclause + ') '
  10878.                     select @unqual_jointable = quotename(name) from sysobjects 
  10879.                         where id = ( select objid from sysmergearticles where name=@join_articlename and pubid=@pubid) 
  10880.        
  10881.                     if @max_network_optimization = 0
  10882.                         select @join_viewname = object_name(sync_objid), @join_before_view = object_name(before_image_objid)
  10883.                             from sysmergearticles where nickname = @join_nick and pubid = @pubid
  10884.                     else
  10885.                         select @join_viewname = object_name(sync_objid), 
  10886.                                    @join_before_view = object_name(case when before_view_objid is not null then before_view_objid else before_image_objid end)
  10887.                                     from sysmergearticles where nickname = @join_nick and pubid = @pubid
  10888.                     
  10889.                     select @join_viewname = QUOTENAME(@join_viewname)
  10890.                     if 1=@hasguid
  10891.                     begin
  10892.                         set @view_rule = ' union select ' + @source_object + '.rowguidcol from ' + @source_object + ', ' +  @join_viewname + ' ' + @unqual_jointable + ' where (' + @join_filterclause
  10893.                                         + ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'
  10894.                         insert into #viewcmd(phase, cmdtext) values(5, @view_rule)
  10895.                     end
  10896.  
  10897.                        if @before_name is not null
  10898.                        begin
  10899.                         set @before_view_rule = ' or exists (select * from ' + @join_viewname + ' ' 
  10900.                                                     + @unqual_jointable + ' where ' + @join_filterclause + ') or exists (select * from '
  10901.                                                     + @join_before_view + ' ' + @unqual_jointable + ' where ' + @join_filterclause + ') '
  10902.                         insert into #beforeviewcmd(phase, cmdtext) values(3, @before_view_rule)
  10903.                      end
  10904.                      
  10905.                     fetch next from pub1 into @join_filterclause, @join_nick, @join_articlename, @join_unique_key, @join_filterid
  10906.                 end 
  10907.                 close pub1
  10908.                 deallocate pub1
  10909.                         
  10910.                 if len(@bool_filterclause) > 0
  10911.                 begin
  10912.                     if 1=@hasguid
  10913.                     begin
  10914.                         set @view_rule = ' union select ' + @source_object + '.rowguidcol from '+ @source_object + ' where ('+ @bool_filterclause
  10915.                                         + ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'
  10916.                         insert into #viewcmd(phase, cmdtext) values(5, @view_rule)
  10917.                     end
  10918.  
  10919.                        if @before_name is not null
  10920.                        begin
  10921.                         set @before_view_rule = ' or ' + @bool_filterclause
  10922.                         insert into #beforeviewcmd(phase,cmdtext) values(3,@before_view_rule)
  10923.                     end
  10924.                 end
  10925.  
  10926.                 if 1=@hasguid
  10927.                 begin
  10928.                     -- Now do the actual view rule as a semi-join, if not a simple join on unique key
  10929.                     if (@simple_join_view = 0)
  10930.                     begin
  10931.                         /* 
  10932.                         ** Generate a unique alias for the outer select to make sure that it does not generate an
  10933.                         ** ambiguous reference with table names used in the join_filter clause 
  10934.                         */
  10935.                         set @alias_for_sourceobject = 'alias_' + @guidstr
  10936.  
  10937.                         set @view_rule= 'select '
  10938.                         insert into #viewcmd(phase, cmdtext) values (2, @view_rule)
  10939.  
  10940.                         -- Here we cannot reuse the original call to sp_MSgetcolumnlist, because
  10941.                         -- it was done with default value for @guid_alias.
  10942.                         insert into #viewcmd(phase, cmdtext) 
  10943.                             exec dbo.sp_MSgetcolumnlist 
  10944.                                         @pubid=@pubid,
  10945.                                         @column_list=@prefixed_column_list output,
  10946.                                         @source_objid=@source_objid,
  10947.                                         @guid_alias=@alias_for_sourceobject,
  10948.                                         @phase=2
  10949.  
  10950.                         set @view_rule= ' from ' + @source_object + ' ' + @alias_for_sourceobject + ' where rowguidcol in ('
  10951.                         insert into #viewcmd(phase,cmdtext) values(2,@view_rule)
  10952.  
  10953.                         set @view_rule= ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'
  10954.                         insert into #viewcmd(phase, cmdtext) values(6, @view_rule)
  10955.                     end
  10956.                 end
  10957.             end
  10958.             else  /* boolean filter only */
  10959.             begin
  10960.                 if 1=@hasguid
  10961.                 begin
  10962.                     delete from #viewcmd where phase<>@tempcollistphase
  10963.                     delete from #beforeviewcmd
  10964.                     
  10965.                     set @view_rule= 'select '
  10966.                     insert into #viewcmd(phase,cmdtext) values (2, @view_rule)
  10967.  
  10968.                     -- sp_MSgetcolumnlist was called at the beginning of the article loop.
  10969.                     -- Thus, we now just set the right phase.
  10970.                     update #viewcmd set phase= 3 where phase=@tempcollistphase
  10971.  
  10972.                     select @view_rule= ' from '+ @source_object + ' ' + @unqual_sourcename + ' where ('+ @bool_filterclause
  10973.                                     + ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'
  10974.                     insert into #viewcmd(phase, cmdtext) values (3, @view_rule)
  10975.                 end
  10976.  
  10977.                 if @before_name is not null
  10978.                 begin
  10979.                     set @before_view_rule = ' select * from ' + @before_name + ' ' + @unqual_sourcename + ' where (' + @bool_filterclause
  10980.                     insert into #beforeviewcmd(phase, cmdtext) values(3, @before_view_rule)
  10981.                 end
  10982.             end
  10983.  
  10984.             select @viewname = @publication + '_' + @article + '_VIEW'
  10985.             exec @retcode = dbo.sp_MSuniqueobjectname @viewname , @viewname output
  10986.             if @retcode <> 0 or @@ERROR <> 0 return (1) 
  10987.  
  10988.             select @quoted_obj = QUOTENAME(@viewname)
  10989.             
  10990.             /* If we havent generated rowguidcol yet, use dummy rule that doesnt refer to it */
  10991.             if @hasguid = 0
  10992.             begin
  10993.                 delete from #viewcmd where phase<>@tempcollistphase
  10994.                 
  10995.                 set @view_rule= 'select '
  10996.                 insert into #viewcmd(phase, cmdtext) values (2, @view_rule)
  10997.  
  10998.                 -- sp_MSgetcolumnlist was called at the beginning of the article loop.
  10999.                 -- Thus, we now just set the right phase.
  11000.                 update #viewcmd set phase= 3 where phase=@tempcollistphase
  11001.  
  11002.                 set @view_rule= ' from '+ @source_object + ' ' + @unqual_sourcename
  11003.                             + ' where ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'
  11004.                 insert into #viewcmd(phase, cmdtext) values (3, @view_rule)
  11005.             end
  11006.  
  11007.             set @view_rule= 'create view '+ @quoted_obj + ' as '
  11008.             insert into #viewcmd(phase,cmdtext) values(1,@view_rule)
  11009.  
  11010.             exec @retcode= master.dbo.xp_execresultset
  11011.                                 @cmd= @viewexeccmd,
  11012.                                 @dbname= @dbname
  11013.             if @@error<>0 or @retcode<>0 return 1
  11014.  
  11015.             /* grant select permission on sync view to public - security check is performed inside the view */ 
  11016.             exec ('grant select on ' + @quoted_obj + ' to public')
  11017.             if @@ERROR<>0
  11018.                 return (1)
  11019.  
  11020.             /* Mark view as system object */                        
  11021.             execute sp_MS_marksystemobject @quoted_obj
  11022.             if @@ERROR<>0
  11023.                 return (1)
  11024.             if @hasguid = 1
  11025.             begin
  11026.                 select @procname=view_sel_proc from sysmergearticles where pubid=@pubid and artid=@artid
  11027.                 if object_id(@procname) is not NULL
  11028.                 begin
  11029.                     set @quoted_obj= quotename(@procname)
  11030.                     exec ('drop procedure ' + @quoted_obj)
  11031.                     update sysmergearticles set view_sel_proc = NULL where artid = @artid and pubid = @pubid 
  11032.                 end
  11033.                 else
  11034.                 begin
  11035.                     set @procname = 'sel_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16)
  11036.                     exec @retcode = dbo.sp_MSuniqueobjectname @procname , @procname output
  11037.                     if @retcode <> 0 or @@ERROR <> 0
  11038.                             return (1)
  11039.                 end
  11040.                 select @owner = user_name(uid) from sysobjects 
  11041.                     where name = @viewname 
  11042.                 exec dbo.sp_MSmakeviewproc @viewname, @owner, @procname, @rgcol, @source_objid
  11043.                 if @retcode<>0 or @@ERROR<>0
  11044.                     return (1)
  11045.                 update sysmergearticles set view_sel_proc = @procname where pubid=@pubid and artid=@artid
  11046.             end
  11047.             select @quoted_obj = QUOTENAME(@viewname)
  11048.             update sysmergearticles set sync_objid = OBJECT_ID (@quoted_obj), view_type = @permanent
  11049.                 where artid = @artid and pubid = @pubid 
  11050.             if @before_name is not null and @before_view_rule is not null
  11051.             begin
  11052.                 set @quoted_obj= quotename(@before_viewname)
  11053.  
  11054.                 exec @retcode = sp_MScreatebeforetable @source_objid
  11055.                 if @@ERROR <>0 OR @retcode <>0 return (1)
  11056.  
  11057.                 if object_id(@before_viewname) is not NULL
  11058.                 begin
  11059.                     exec ('drop view ' + @quoted_obj)            
  11060.                 end
  11061.                 
  11062.                 set @before_view_rule= ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'
  11063.  
  11064.                 insert into #beforeviewcmd(phase,cmdtext) values(5,@before_view_rule)
  11065.                 set @before_view_rule= 'create view ' + @quoted_obj + ' as '
  11066.  
  11067.                 insert into #beforeviewcmd(phase,cmdtext) values(2,@before_view_rule)
  11068.  
  11069.                 exec @retcode= master.dbo.xp_execresultset
  11070.                                     @cmd= @beforeviewexeccmd,
  11071.                                     @dbname= @dbname
  11072.                 if @@error<>0 or @retcode<>0 return 1
  11073.             
  11074.                 if @before_rowguidname is not NULL
  11075.                 begin
  11076.                     set @quoted_rowguid= quotename(@before_rowguidname)
  11077.                     exec ('grant select (' + @quoted_rowguid + ') on '+ @quoted_obj + ' to public')
  11078.                     if @@ERROR<>0
  11079.                         return (1)
  11080.                 end
  11081.  
  11082.                 exec ('grant select (generation) on '+ @quoted_obj + ' to public')
  11083.                 if @@ERROR<>0
  11084.                     return (1)
  11085.  
  11086.                 execute sp_MS_marksystemobject @before_viewname
  11087.                 if @@ERROR<>0
  11088.                     return (1)
  11089.                 update sysmergearticles set before_view_objid = OBJECT_ID (@before_viewname)
  11090.                     where artid = @artid and pubid = @pubid
  11091.             end
  11092.         end
  11093.         else 
  11094.         begin
  11095.             select @sync_objid = @source_objid
  11096.             if @vertical_partition=1 and 0=@allcolsreturned
  11097.             begin
  11098.                 select @viewname = @publication + '_' + @article + '_VIEW'
  11099.                 exec @retcode = dbo.sp_MSuniqueobjectname @viewname , @viewname output
  11100.                 select @quoted_obj = QUOTENAME(@viewname)
  11101.  
  11102.                 set @view_rule= 'create view '+ @quoted_obj + ' as '+ ' select '
  11103.                 insert into #viewcmd(phase, cmdtext) values (1, @view_rule)
  11104.  
  11105.                 -- sp_MSgetcolumnlist was called at the beginning of the article loop.
  11106.                 -- Thus, we now just set the right phase.
  11107.                 update #viewcmd set phase= 2 where phase=@tempcollistphase
  11108.  
  11109.                 set @view_rule= ' from '+ @source_object + ' ' + @unqual_sourcename
  11110.                                 + ' where ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'
  11111.                 insert into #viewcmd(phase, cmdtext) values (2, @view_rule)
  11112.  
  11113.                 exec @retcode= master.dbo.xp_execresultset
  11114.                                     @cmd= @viewexeccmd,
  11115.                                     @dbname= @dbname
  11116.                 if @@error<>0 or @retcode<>0 return 1
  11117.                 
  11118.                 execute sp_MS_marksystemobject @quoted_obj
  11119.                 if @@ERROR<>0
  11120.                     return (1)
  11121.  
  11122.                 /* grant select permission on sync view to public - security check is performed inside the view */ 
  11123.                 exec ('grant select on ' + @quoted_obj + ' to public')
  11124.                 if @@ERROR<>0 return (1)
  11125.                 
  11126.                 select @sync_objid=object_id(@viewname)
  11127.                 update sysmergearticles set view_sel_proc = @procname, sync_objid=@sync_objid
  11128.                     where artid = @artid and pubid = @pubid 
  11129.             end
  11130.             else if @dynamic_filters = 1
  11131.             begin
  11132.                 /* This article doesn't have any vertical or horizontal filters but if the publication is enabled for dynamic filtering, 
  11133.                     we still want to generate a dummy view so that logins in the publication access list can generate a dynamic snapshot. */
  11134.                 select @viewname = @publication + '_' + @article + '_VIEW'
  11135.                 exec @retcode = dbo.sp_MSuniqueobjectname @viewname, @viewname output
  11136.                 select @quoted_obj = QUOTENAME(@viewname)
  11137.                 set @view_rule = ' select  * from ' + @source_object  + ' where ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'     
  11138.                 exec ('create view '+ @quoted_obj + ' as '+ @view_rule)
  11139.                 if @@ERROR<>0
  11140.                     return (1)
  11141.                 execute sp_MS_marksystemobject @quoted_obj
  11142.                 if @@ERROR<>0
  11143.                     return (1)
  11144.                 exec ('grant select on ' + @quoted_obj + ' to public')
  11145.                 if @@ERROR<>0
  11146.                     return (1)
  11147.                 select @sync_objid=object_id(@viewname)
  11148.                 update sysmergearticles set view_sel_proc = @procname, sync_objid=@sync_objid, view_type = @permanent
  11149.                 where artid = @artid and pubid = @pubid 
  11150.             end
  11151.  
  11152.             if @hasguid = 1
  11153.             begin
  11154.                 /* still make the select proc, although it selects directly from table */
  11155.                 if object_id(@procname) is not NULL
  11156.                 begin
  11157.                     set @quoted_obj= quotename(@procname)
  11158.                     exec ('drop proc ' + @quoted_obj)
  11159.                     update sysmergearticles set view_sel_proc = NULL where artid = @artid and pubid = @pubid 
  11160.                 end
  11161.                 
  11162.                 set @procname = 'sel_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16)
  11163.                 exec @retcode = dbo.sp_MSuniqueobjectname @procname , @procname output
  11164.                 if @retcode <> 0 or @@ERROR <> 0 return (1) 
  11165.                 select @owner = user_name(uid), @viewname = name from sysobjects 
  11166.                     where id = @sync_objid
  11167.                 exec dbo.sp_MSmakeviewproc @viewname, @owner, @procname, @rgcol, @source_objid
  11168.                 update sysmergearticles set view_sel_proc = @procname where pubid=@pubid and artid=@artid
  11169.             end
  11170.         end
  11171.         select @art=min(indexcol) from #art where indexcol>@art
  11172.     end
  11173.  
  11174.     /* If there are looping articles, we must use a dynamic publication since no views on temp tables */
  11175.     update sysmergearticles set view_type = @temporary
  11176.         where pubid=@pubid and nickname not in (select art_nick from #art)
  11177.     if @@rowcount > 0
  11178.     begin
  11179.         if not exists (select * from sysmergepublications where dynamic_filters = 1 and pubid = @pubid)
  11180.         begin
  11181.             declare @repl_nick int
  11182.             /* treat these articles as if the publication were dynamic */
  11183.             execute @retcode = dbo.sp_MSgetreplnick @nickname = @repl_nick output
  11184.             if (@@error <> 0) or @retcode <> 0 or @repl_nick IS NULL 
  11185.             begin
  11186.                 RAISERROR (14055, 11, -1)
  11187.                 RETURN(1)
  11188.             end                 
  11189.  
  11190.             select @art_nick = min(nickname) from sysmergearticles where
  11191.                 pubid = @pubid and view_type = @temporary
  11192.             while @art_nick is not null
  11193.             begin
  11194.                 /* Loop over articles with circular filters.  Create dummy view and add rows to contents */
  11195.                 select @article = name, @artid = artid, @source_objid = objid, @sync_objid = sync_objid, @procname = view_sel_proc from sysmergearticles 
  11196.                     where nickname=@art_nick and pubid = @pubid
  11197.                 select @source_object = QUOTENAME(user_name(uid)) + '.' + QUOTENAME(name) from sysobjects 
  11198.                     where id = @source_objid 
  11199.  
  11200.                 set @viewname = NULL
  11201.                 select @viewname =  name from sysobjects where id = @sync_objid and
  11202.                     ObjectProperty (id, 'IsView') = 1  and
  11203.                     ObjectProperty (id, 'IsMSShipped') = 1 
  11204.                 if @viewname IS NOT NULL
  11205.                 begin
  11206.                     select @quoted_obj = QUOTENAME(@viewname)
  11207.                     exec ('drop view ' + @quoted_obj)
  11208.                     if @@ERROR<>0 return (1)
  11209.                 end
  11210.                 select @viewname = 'SYNC_' + @publication + '_' + @article 
  11211.                 exec @retcode = dbo.sp_MSuniqueobjectname @viewname , @viewname output
  11212.                 if @retcode <> 0 or @@ERROR <> 0 return (1) 
  11213.                 select @quoted_obj = QUOTENAME(@viewname)
  11214.                 exec ('create view ' + @quoted_obj + ' as select * from ' + @source_object + ' 
  11215.                         where 1 = 0 ')
  11216.                 if @@ERROR<>0 return (1)
  11217.                 update sysmergearticles set sync_objid = OBJECT_ID (@viewname),
  11218.                     view_sel_proc = NULL where artid = @artid and pubid = @pubid 
  11219.                 if @@ERROR<>0 return (1)
  11220.  
  11221.                 select @owner = user_name(uid) from sysobjects where id = @source_objid
  11222.                 set @table = OBJECT_NAME(@source_objid)
  11223.                 exec @retcode = dbo.sp_addtabletocontents @table, @owner
  11224.                 IF @@ERROR <> 0 or @retcode <> 0 return (1)
  11225.                 
  11226.                 select @art_nick = min(nickname) from sysmergearticles where
  11227.                     pubid = @pubid and view_type = @temporary and nickname > @art_nick
  11228.             end
  11229.         end
  11230.     end
  11231.         
  11232.     drop table #art
  11233.     if @allhaveguids = 1
  11234.     begin
  11235.         /* create the filter expand procs now */
  11236.         set @filter_id = 0
  11237.         select @filter_id = min(join_filterid) from sysmergesubsetfilters where
  11238.                 pubid = @pubid and join_filterid > @filter_id
  11239.         while @filter_id is not null
  11240.         begin
  11241.             set @filter_id_str = convert(nvarchar(10), @filter_id)
  11242.             select @procname = expand_proc
  11243.                 from sysmergesubsetfilters where pubid = @pubid and join_filterid = @filter_id
  11244.  
  11245.             /* drop old proc, or generate a new procname */
  11246.             if object_id(@procname) is not NULL
  11247.             begin
  11248.                 set @quoted_obj= quotename(@procname)
  11249.                 exec ('drop procedure ' + @quoted_obj)
  11250.             end
  11251.             else
  11252.             begin
  11253.                 set @procname = 'expand_' + @filter_id_str
  11254.                 exec @retcode = dbo.sp_MSuniqueobjectname @procname, @procname output
  11255.                 if @retcode <>0 return (1)
  11256.                 update sysmergesubsetfilters set expand_proc = @procname where  pubid = @pubid and join_filterid = @filter_id
  11257.             end
  11258.             set @command = 'exec dbo.sp_MSmakeexpandproc ' + quotename(@publication) + ' , ' + @filter_id_str + ', ' + quotename(@procname)
  11259.             exec @retcode = master..xp_execresultset @command, @dbname
  11260.             if @retcode <> 0 return (1)
  11261.             exec dbo.sp_MS_marksystemobject @procname
  11262.             if @@ERROR<>0
  11263.                 return (1)
  11264.             set @quoted_obj= quotename(@procname)
  11265.             exec ('grant execute on ' + @quoted_obj + ' to public ')
  11266.             select @filter_id = min(join_filterid) from sysmergesubsetfilters where
  11267.                 pubid = @pubid and join_filterid > @filter_id
  11268.         end
  11269.     end
  11270.  
  11271.     return (0)
  11272.  
  11273. FAILURE: 
  11274.     return (1)
  11275. go
  11276. exec dbo.sp_MS_marksystemobject sp_MSpublicationview
  11277. go
  11278. grant execute on dbo.sp_MSpublicationview to public
  11279. go
  11280.  
  11281. dump tran master with no_log
  11282. go
  11283.  
  11284. raiserror('Creating procedure sp_addmergesubscription', 0,1)
  11285. GO
  11286. CREATE PROCEDURE sp_addmergesubscription (
  11287.     @publication                    sysname,                    /* Publication name */
  11288.     @subscriber                     sysname = NULL,             /* Subscriber server */
  11289.     @subscriber_db                  sysname = NULL,             /* Subscription database */
  11290.     @subscription_type              nvarchar(15) = 'push',          /* Subscription type - push, pull */ 
  11291.     @subscriber_type                nvarchar(15) = 'local',         /* Subscriber type */ 
  11292.     @subscription_priority          real        = NULL,             /* Subscription priority */
  11293.     @sync_type                      nvarchar(15) = 'automatic',     /* subscription sync type */
  11294.     @frequency_type                 int = NULL,            
  11295.     @frequency_interval             int = NULL,        
  11296.     @frequency_relative_interval    int = NULL,
  11297.     @frequency_recurrence_factor    int = NULL,
  11298.     @frequency_subday               int = NULL,            
  11299.     @frequency_subday_interval      int = NULL,
  11300.     @active_start_time_of_day       int = NULL,
  11301.     @active_end_time_of_day         int = NULL,
  11302.     @active_start_date              int = NULL,
  11303.     @active_end_date                int = NULL,
  11304.     @optional_command_line          nvarchar(4000) = NULL,
  11305.     @description                    nvarchar(255) = NULL,
  11306.     @enabled_for_syncmgr            nvarchar(5) = 'false', /* Enabled for SYNCMGR: true or false */
  11307.     -- Agent offload
  11308.     @offloadagent                   bit = 0,
  11309.     @offloadserver                  sysname = NULL,
  11310.     @use_interactive_resolver        nvarchar(5) = 'false',
  11311.     @merge_job_name                    sysname = NULL
  11312.     ) AS
  11313.  
  11314.     SET NOCOUNT ON
  11315.  
  11316.     /*
  11317.     ** Declarations.
  11318.     */
  11319.     declare @retcode                int
  11320.     declare @subnickname            int
  11321.     declare @subscriber_srvid       int 
  11322.     declare @publisher_srvid        int 
  11323.     declare @priority               real
  11324.     declare @subid                  uniqueidentifier
  11325.     declare @pubid                  uniqueidentifier    /* Publication id */
  11326.     declare @subscriber_typeid      smallint
  11327.     declare @merge_jobid            binary(16)          /* Scheduler jobid for the merge agent */
  11328.     declare @subscription_type_id   int   
  11329.     declare @distproc               nvarchar(300)
  11330.     declare @command                nvarchar(255)
  11331.     declare @inactive               tinyint
  11332.     declare @subscriber_bit         smallint
  11333.     declare @global                 tinyint     /* subscriber type is global */
  11334.     declare @push                   tinyint     /* subscription type is push */
  11335.     declare @partnerid              uniqueidentifier    /* Partner replica identifier */
  11336.     declare @sync_typeid            tinyint
  11337.     declare @nosync                 tinyint     
  11338.     declare @automatic              tinyint     
  11339.     declare @distributor            sysname
  11340.     declare @distribdb              sysname
  11341.     declare @publisher              sysname
  11342.     declare @publisher_db           sysname
  11343.     declare @found                  int
  11344.     declare @datasource_type        int
  11345.     declare @datasource_path        sysname
  11346.     DECLARE @platform_nt            binary
  11347.     declare @datasrctype            int
  11348.     declare @datasrcpath            sysname
  11349.     declare @use_interactive_bit    bit
  11350.  
  11351.     
  11352.     /* make sure current database is enabled for merge replication */
  11353.     exec @retcode=dbo.sp_MSCheckmergereplication
  11354.     if @@ERROR<>0 or @retcode<>0
  11355.         return (1)
  11356.  
  11357.     /*
  11358.     ** Initializations.
  11359.     */
  11360.     set @datasource_type = 0    /* Default SQL Server */
  11361.     set @datasource_path = NULL 
  11362.     set @datasrctype = 0    /* Default SQL Server */
  11363.     set @datasrcpath = NULL 
  11364.     set @platform_nt = 0x1  
  11365.     SET @nosync             = 2       /* Const: synchronization type 'none' */
  11366.     SET @automatic          = 1       /* Const: synchronization type 'automatic' */
  11367.     set @inactive           = 0
  11368.     SET @subscriber_bit     = 4  
  11369.     set @global             = 1
  11370.     set @push               = 0
  11371.     set @pubid              = NULL         
  11372.     set @publisher          = @@SERVERNAME
  11373.     set @publisher_db       = DB_NAME()
  11374.     select @found           = 1    /* Any non-NULL value is fine */
  11375.     /*
  11376.     ** Parameter Check: @subscription_type.
  11377.     ** Set subscriber_typeid based on the @subscription_type specified.
  11378.     **
  11379.     **   subscription_type    subscription_type
  11380.     **   =================    ===============
  11381.     **             0            push
  11382.     **             1            pull
  11383.     */
  11384.     if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('push', 'pull')
  11385.         BEGIN
  11386.             RAISERROR (14128, 16, -1)
  11387.             RETURN (1)
  11388.         END
  11389.     IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push'
  11390.         set @subscription_type_id = 0
  11391.     else 
  11392.         set @subscription_type_id = 1
  11393.  
  11394.  
  11395.     /*
  11396.     ** Parameter check: @offloadagent
  11397.     ** If @offloadagent = 1 then @subscription_type_id must be 0 
  11398.     */
  11399.     IF (@offloadagent = 1) AND (@subscription_type <> N'push') 
  11400.     BEGIN
  11401.         RAISERROR(21138, 16, -1)
  11402.         RETURN (1)
  11403.     END 
  11404.  
  11405.     /*
  11406.     ** Security Check.
  11407.     */
  11408.  
  11409.     IF @subscription_type_id = 0 
  11410.     BEGIN
  11411.         exec @retcode = dbo.sp_MSreplcheck_publish
  11412.         if @@ERROR <> 0 or @retcode <> 0
  11413.             return(1)
  11414.     END
  11415.     ELSE
  11416.     BEGIN
  11417.         exec @retcode = dbo.sp_MSreplcheck_pull @publication
  11418.         if @@ERROR <> 0 or @retcode <> 0
  11419.         begin
  11420.             return(1)
  11421.         end
  11422.     END
  11423.  
  11424.     /*
  11425.     ** Validate that the publisher is a valid server
  11426.     */
  11427.     select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
  11428.     IF @publisher_srvid IS NULL
  11429.         BEGIN
  11430.             RAISERROR (14010, 16, -1)
  11431.             RETURN (1)
  11432.         END
  11433.  
  11434.     /*
  11435.     ** Parameter Check: @subscriber
  11436.     ** Check to make sure that the subscriber is defined
  11437.     */
  11438.     IF @subscriber IS NULL
  11439.         BEGIN
  11440.             RAISERROR (14043, 16, -1, '@subscriber')
  11441.             RETURN (1)
  11442.         END
  11443.  
  11444.      IF NOT EXISTS (SELECT * FROM master..sysservers WHERE UPPER(srvname) = UPPER(@subscriber) collate database_default
  11445.                      AND (srvstatus & @subscriber_bit) <> 0)
  11446.                BEGIN
  11447.                    RAISERROR (14010, 16, -1)
  11448.                    RETURN (1)
  11449.                END
  11450.  
  11451.     IF @subscriber = 'all'
  11452.         BEGIN
  11453.             RAISERROR (14136, 16, -1)
  11454.             RETURN (1)
  11455.         END
  11456.  
  11457.     /*
  11458.     ** Get distribution server information for remote RPC call.
  11459.     */
  11460.     EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
  11461.          @distribdb   = @distribdb OUTPUT
  11462.     IF @@ERROR <> 0 or @retcode <> 0
  11463.         BEGIN
  11464.         GOTO FAILURE
  11465.         END
  11466.  
  11467.         SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + 
  11468.             '.dbo.sp_MShelp_subscriber_info '
  11469.     exec @distproc @publisher, @subscriber, @found output
  11470.     if (@found <> 1) 
  11471.         BEGIN
  11472.             RAISERROR (14085, 16, -1)
  11473.             RETURN (1)
  11474.         END
  11475.  
  11476.     exec @retcode = dbo.sp_MSget_subtypedatasrc @subscriber, @distributor, @distribdb, @datasrctype OUTPUT, @datasrcpath OUTPUT
  11477.     if @retcode<>0
  11478.         return (1)
  11479.     if (@datasrctype = 2) or (@datasrctype = 4) or (@datasrctype = 5)
  11480.     BEGIN
  11481.         select @datasource_type = @datasrctype
  11482.         select @datasource_path = @datasrcpath
  11483.     END
  11484.     
  11485.     EXECUTE @retcode = dbo.sp_validname @subscriber
  11486.     IF @@ERROR <> 0 OR @retcode <> 0
  11487.        RETURN (1)
  11488.  
  11489.     /*
  11490.     ** Parameter Check: @subscriber_db
  11491.     */
  11492.     IF @subscriber_db IS NULL
  11493.     BEGIN
  11494.         RAISERROR (14043, 16, -1, '@subscriber_db')
  11495.         RETURN (1)
  11496.     END
  11497.  
  11498.     IF @subscriber_db = 'all'
  11499.     BEGIN
  11500.         RAISERROR (14136, 16, -1)
  11501.         RETURN (1)
  11502.     END
  11503.  
  11504.     /*
  11505.     **  Check to see if system tables exist. If not create them. Since under current
  11506.     **  design every database is qualified for subscribing.
  11507.     */
  11508.     
  11509.     IF not exists (select name from sysobjects where name='sysmergesubscriptions')
  11510.         BEGIN
  11511.             execute @retcode = dbo.sp_MScreate_mergesystables
  11512.                 if @@ERROR <> 0 or @retcode <> 0
  11513.                     begin
  11514.                         return (1)
  11515.                     end
  11516.         END 
  11517.         
  11518.     /*
  11519.     ** Parameter Check: @publication.
  11520.     ** Check to make sure that the publication exists and that it conforms
  11521.     ** to the rules for identifiers.
  11522.     */
  11523.     if NOT EXISTS (select * FROM sysmergepublications 
  11524.         WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name())
  11525.         BEGIN
  11526.             RAISERROR (20026, 16, -1, @publication)
  11527.             RETURN (1)
  11528.         END
  11529.  
  11530.     if @pubid IS NULL
  11531.         select @pubid = pubid FROM sysmergepublications 
  11532.             WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  11533.     if @partnerid IS NULL
  11534.         begin
  11535.             select @partnerid = subid FROM sysmergesubscriptions 
  11536.                 WHERE srvid = @publisher_srvid and db_name = @publisher_db and pubid = @pubid
  11537.         end                     
  11538.  
  11539.     /*
  11540.     ** Parameter Check: @subscriber_type.
  11541.     ** Set subscriber_typeid based on the @subscriber_type specified.
  11542.     **
  11543.     **   subscriber_type     subscriber_type
  11544.     **   =================    ===============
  11545.     **             1            global
  11546.     **             2            local
  11547.     **             3            anonymous
  11548.     **                          Type 'republisher' is taken out for B3. We may want to add this back later.
  11549.     */
  11550.     if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('local', 'global')
  11551.         BEGIN
  11552.             RAISERROR (20037, 16, -1)
  11553.             RETURN (1)
  11554.         END
  11555.  
  11556.     if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('global')
  11557.         set @subscriber_typeid = 1
  11558.     else if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('local')
  11559.         set @subscriber_typeid = 2
  11560.  
  11561.        /*
  11562.     ** Parameter Check: @use_interactive_resolver  
  11563.     */
  11564.     if LOWER(@use_interactive_resolver collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  11565.         BEGIN
  11566.             RAISERROR (14148, 16, -1, '@use_interactive_resolver')
  11567.             RETURN (1)
  11568.         END
  11569.     if LOWER(@use_interactive_resolver collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  11570.         set @use_interactive_bit = 1
  11571.     else 
  11572.         set @use_interactive_bit = 0
  11573.  
  11574.     
  11575.     /* 
  11576.     ** Assign priority appropriately - choose 0.99 times the minimum priority
  11577.     ** of the global replicas.
  11578.     */
  11579.     if (@subscription_priority >= 100.0 or @subscription_priority < 0.0)
  11580.         BEGIN
  11581.             RAISERROR (20088, 16, -1)
  11582.             RETURN (1)
  11583.         END
  11584.     if (@subscription_priority IS NULL)
  11585.         begin
  11586.             select @priority = 0.99 * min(priority) from sysmergesubscriptions where subscriber_type = 1
  11587.             if (@priority IS NOT NULL)
  11588.                 select @subscription_priority = @priority
  11589.             if (@subscription_priority IS NULL) 
  11590.                 select @subscription_priority = 0.0
  11591.         end
  11592.     /*
  11593.     ** For local and anonymous subscriptions the priority is 0.0
  11594.     */
  11595.     if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('local', 'anonymous')
  11596.         select @subscription_priority = 0.0
  11597.     
  11598.     /*
  11599.     ** Validate that the subscriber is a valid server
  11600.     */
  11601.     select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
  11602.     IF @subscriber_srvid IS NULL
  11603.         BEGIN
  11604.             RAISERROR (14010, 16, -1)
  11605.             RETURN (1)
  11606.         END
  11607.  
  11608.     IF exists (select * from sysobjects where name= 'syssubscriptions')
  11609.     begin
  11610.         if exists (select name from sysmergeextendedarticlesview where pubid=@pubid and objid in
  11611.             (select objid from sysextendedarticlesview where artid in
  11612.                 (select artid from syssubscriptions where dest_db=@subscriber_db and srvid=@subscriber_srvid)))
  11613.         begin
  11614.             RAISERROR(21280, 16, -1, @publication, @subscriber_db)
  11615.             RETURN (1)
  11616.         end
  11617.     end
  11618.  
  11619.  
  11620.     /* 
  11621.     ** Make sure that @offloadserver doesn't contain invalid characters
  11622.     */
  11623.     exec @retcode = sp_MSreplcheckoffloadserver @offloadserver
  11624.     if @retcode<>0 or @@error<>0
  11625.         return (1)
  11626.  
  11627.     /*
  11628.     ** Making it possible for a deleted subscription to come back.
  11629.     ** UNDONE : This disallows second pull subscription from being added unless the previous 
  11630.     ** subscription was initial synced.
  11631.     */
  11632.     if EXISTS (select db_name, srvid
  11633.             FROM sysmergesubscriptions
  11634.             WHERE db_name = @subscriber_db
  11635.             AND srvid = @subscriber_srvid                          
  11636.             AND pubid = @pubid AND status <>2) --We can definitely add back subscriptions that were deleted.
  11637.         BEGIN
  11638.             RAISERROR (14058, 16, -1)
  11639.             RETURN (1)
  11640.         END
  11641.         
  11642.     IF EXISTS (select db_name, srvid FROM sysmergesubscriptions 
  11643.         WHERE db_name = @subscriber_db AND srvid = @subscriber_srvid AND pubid = @pubid AND status = 2) 
  11644.             BEGIN
  11645.                 select @subid = subid from sysmergesubscriptions 
  11646.                     WHERE db_name = @subscriber_db AND srvid = @subscriber_srvid AND pubid = @pubid
  11647.                 delete  from sysmergesubscriptions where subid = @subid
  11648.                 delete from MSmerge_replinfo where repid = @subid
  11649.             END
  11650.     select @subid = newid()    
  11651.     
  11652.    /*
  11653.    ** Parameter Check: @sync_type.
  11654.    ** Set sync_typeid based on the @sync_type specified.
  11655.    **
  11656.    **   sync_typeid     sync_type
  11657.    **   ===========     =========
  11658.    **             1     automatic
  11659.    **             2     none
  11660.    */
  11661.  
  11662.  
  11663.    IF LOWER(@sync_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('automatic', 'none')
  11664.        BEGIN
  11665.            RAISERROR (14052, 16, -1)
  11666.            RETURN (1)
  11667.        END
  11668.  
  11669.  
  11670.     /*
  11671.     ** If current publication contains an article without rowguidcol, do not allow no-sync subscription
  11672.     */
  11673.    IF LOWER(@sync_type collate SQL_Latin1_General_CP1_CS_AS) = 'automatic'
  11674.    BEGIN
  11675.         SET @sync_typeid = @automatic
  11676.    END
  11677.    ELSE
  11678.    BEGIN
  11679.         if exists (select * from sysmergearticles a where pubid=@pubid and 
  11680.             not exists (select * from syscolumns c where c.id = a.objid and ColumnProperty(c.id, c.name, 'IsRowGuidCol') = 1))
  11681.             
  11682.             BEGIN
  11683.                 Raiserror(20086, 16, -1, @publication)
  11684.                 RETURN (1)
  11685.             END
  11686.         else 
  11687.             SET @sync_typeid = @nosync
  11688.    END
  11689.  
  11690.  
  11691.     /*
  11692.     ** UNDONE: Validate that the publisher is of type "republisher"
  11693.     */
  11694.     begin tran
  11695.     save TRAN addmergesubscription
  11696.         /* Generate a guid for the Subscriber ID */
  11697.     
  11698.         /* Look for existing nickname from any other subscription */
  11699.         exec @retcode = dbo.sp_MSgetreplnick @subscriber, @subscriber_db , NULL,  @subnickname out
  11700.         if (@@error <> 0) or @retcode <> 0 
  11701.             GOTO FAILURE
  11702.             
  11703.         /* Generate a new replica nickname from the @subid */
  11704.         if (@subnickname is null)
  11705.         begin
  11706.             EXECUTE dbo.sp_MSgenreplnickname @subid, @subnickname output
  11707.             if @@ERROR<>0 
  11708.                 GOTO FAILURE
  11709.         end
  11710.             
  11711.         /*
  11712.         ** The subscription doesn't exist, so let's add it to sysmergesubscriptions 
  11713.         */
  11714.         INSERT sysmergesubscriptions (subid, 
  11715.                                       partnerid,
  11716.                                       datasource_type, 
  11717.                                       datasource_path, 
  11718.                                       srvid, 
  11719.                                       db_name, 
  11720.                                       pubid,
  11721.                                       status, 
  11722.                                       subscriber_type,
  11723.                                       subscription_type,
  11724.                                       priority, 
  11725.                                       sync_type, 
  11726.                                       description,
  11727.                                       login_name,
  11728.                                       subscriber_server,
  11729.                                       use_interactive_resolver,
  11730.                                       publication,
  11731.                                       distributor)
  11732.                         VALUES (@subid,
  11733.                             @partnerid,
  11734.                             @datasource_type,
  11735.                             @datasource_path,
  11736.                             @subscriber_srvid,
  11737.                             @subscriber_db,
  11738.                             @pubid,
  11739.                             @inactive,
  11740.                             @subscriber_typeid,
  11741.                             @subscription_type_id,
  11742.                             @subscription_priority,
  11743.                             @sync_typeid,
  11744.                             @description,
  11745.                             suser_sname(suser_sid()),
  11746.                             @subscriber,
  11747.                             @use_interactive_bit,
  11748.                             @publication,
  11749.                             @distributor)          
  11750.         if @@ERROR <> 0
  11751.             BEGIN
  11752.                 GOTO FAILURE
  11753.             END
  11754.                 
  11755.         /*
  11756.         ** Get distribution server information for remote RPC call.
  11757.         */
  11758.         EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
  11759.            @distribdb   = @distribdb OUTPUT
  11760.         IF @@ERROR <> 0 or @retcode <> 0
  11761.             BEGIN
  11762.                 GOTO FAILURE
  11763.             END
  11764.  
  11765.         SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + 
  11766.             '.dbo.sp_MSadd_merge_subscription'
  11767.         EXEC @retcode = @distproc 
  11768.             @publisher = @@SERVERNAME, 
  11769.             @publisher_db = @publisher_db, 
  11770.             @publication = @publication,
  11771.             @subscriber = @subscriber, 
  11772.             @subscriber_db = @subscriber_db, 
  11773.             @subscription_type = @subscription_type_id,
  11774.             @sync_type = @sync_typeid, 
  11775.             @status = @inactive,
  11776.             @frequency_type = @frequency_type,
  11777.             @frequency_interval = @frequency_interval,
  11778.             @frequency_relative_interval = @frequency_relative_interval,
  11779.             @frequency_recurrence_factor = @frequency_recurrence_factor,
  11780.             @frequency_subday = @frequency_subday,
  11781.             @frequency_subday_interval = @frequency_subday_interval,
  11782.             @active_start_time_of_day = @active_start_time_of_day,
  11783.             @active_end_time_of_day = @active_end_time_of_day,
  11784.             @active_start_date = @active_start_date,
  11785.             @active_end_date = @active_end_date,
  11786.             @optional_command_line = @optional_command_line,
  11787.             @merge_jobid = @merge_jobid OUTPUT,
  11788.             @offloadagent = @offloadagent,
  11789.             @offloadserver = @offloadserver,
  11790.             @agent_name = @merge_job_name  
  11791.             
  11792.         IF @@ERROR <> 0 OR @retcode <> 0
  11793.             begin   
  11794.                 goto FAILURE
  11795.             end
  11796.             
  11797.         /*
  11798.         **  Add row for subscription in MSmerge_replinfo.
  11799.         */
  11800.         insert MSmerge_replinfo(repid, replnickname, merge_jobid)
  11801.                 values (@subid, @subnickname, @merge_jobid)
  11802.         if @@ERROR <> 0
  11803.             BEGIN
  11804.                 GOTO FAILURE
  11805.             END
  11806.  
  11807.         /* Conditional support for MobileSync */
  11808.         if LOWER(@enabled_for_syncmgr collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  11809.         BEGIN
  11810.  
  11811.             /* MobileSync Support */
  11812.             declare @distributor_server                 sysname
  11813.             declare @distributor_security_mode          int
  11814.             declare @distributor_login                  sysname
  11815.             declare @distributor_password               nvarchar(524)
  11816.  
  11817.             /* 
  11818.             ** The registry entry needs to be created only for push subscriptions -  
  11819.             ** i.e - need not be called when a pull subscription is created at the 
  11820.             ** subscriber and sp_addmergesubscription is being called then.
  11821.             */
  11822.             
  11823.             IF @subscription_type_id = 0 
  11824.             BEGIN
  11825.                 EXECUTE @retcode = dbo.sp_helpdistributor
  11826.                     @distributor = @distributor_server OUTPUT               /* Distributor RPC server name */
  11827.                 IF @@ERROR <> 0 or @retcode <> 0
  11828.                     BEGIN
  11829.                         GOTO FAILURE
  11830.                     END
  11831.  
  11832.                 -- Always use integrated security on winNT
  11833.                 if (@platform_nt = platform() & @platform_nt )
  11834.                     begin
  11835.                         set @distributor_security_mode = 1
  11836.                     end
  11837.                 -- For Win9x the dist publisher and distributor are the same machine                
  11838.                 else
  11839.                     begin
  11840.                         select  @distributor_security_mode = 0,
  11841.                             @distributor_login  = login,
  11842.                             @distributor_password = password
  11843.                         from msdb..MSdistpublishers where UPPER(name) = UPPER(@@servername) collate database_default
  11844.                     end
  11845.  
  11846.                 /* Call sp_MSregistersubscription so that the subscription can be synchronized via Onestop etc. */
  11847.                 exec @retcode = dbo.sp_MSregistersubscription @replication_type = 2,
  11848.                                     @publisher = @@SERVERNAME,
  11849.                                     @publisher_db = @publisher_db,
  11850.                                     @publication = @publication,
  11851.                                     @subscriber = @subscriber,
  11852.                                     @subscriber_db = @subscriber_db,
  11853.                                     @distributor = @distributor,
  11854.                                     @distributor_security_mode = @distributor_security_mode,
  11855.                                     @distributor_login = @distributor_login,
  11856.                                     @distributor_password = @distributor_password,
  11857.                                     @subscription_id = @subid,
  11858.                                     @subscription_type = @subscription_type_id,
  11859.                                     @use_interactive_resolver = @use_interactive_bit
  11860.                 IF @@error <> 0 OR @retcode <> 0
  11861.                     BEGIN
  11862.                         GOTO FAILURE
  11863.                     END
  11864.  
  11865.             END                                    
  11866.         END     
  11867.     COMMIT TRAN
  11868.     return (0)
  11869.  
  11870. FAILURE:
  11871.     RAISERROR (14057, 16, -1)
  11872.     /* UNDONE : This code is specific to 6.X nested transaction semantics */
  11873.     if @@TRANCOUNT > 0
  11874.     begin
  11875.         ROLLBACK TRANSACTION addmergesubscription
  11876.         COMMIT TRANSACTION
  11877.     end
  11878.     RETURN (1)
  11879.  
  11880. go
  11881. exec dbo.sp_MS_marksystemobject sp_addmergesubscription 
  11882. go
  11883.  
  11884. grant execute on dbo.sp_addmergesubscription to public
  11885. go
  11886.  
  11887. raiserror('Creating procedure sp_MSretrive_mergepublication', 0,1)
  11888. GO
  11889.  
  11890. CREATE PROCEDURE sp_MSretrieve_mergepublication 
  11891. @publication sysname
  11892. AS
  11893. declare @retcode int
  11894. /*
  11895. ** Security Check
  11896. */
  11897. exec @retcode = dbo.sp_MSreplcheck_publish
  11898. if @@ERROR <> 0 or @retcode <> 0
  11899.     return(1)
  11900.  
  11901. select    'name' = name, 
  11902.         'database ' = db_name(), 
  11903.         'publisher' = @@SERVERNAME, 
  11904.         'type' = 'Merge', 
  11905.         'description ' = description, 
  11906.         'status ' = status,  
  11907.         'allow known pull subscription' = allow_pull, 
  11908.         'allow immediate-updating subscription ' = 0,
  11909.         'allow anonymous ' = allow_anonymous,  
  11910.         'allow queued-updating subscription ' = 0, 
  11911.         'allow snapshot files FTP downloading' = enabled_for_internet, 
  11912.         'third party' = sync_mode 
  11913.     from sysmergepublications
  11914.     where name = @publication
  11915. go
  11916.  
  11917. EXEC dbo.sp_MS_marksystemobject sp_MSretrieve_mergepublication
  11918. GO
  11919.  
  11920. raiserror('Creating procedure sp_changemergesubscription', 0,1)
  11921. GO
  11922.  
  11923. CREATE PROCEDURE sp_changemergesubscription (
  11924.     @publication        sysname = NULL, /* Publication name */
  11925.     @subscriber         sysname = NULL,  /* Subscriber server */
  11926.     @subscriber_db      sysname = NULL,  /* Subscription database */
  11927.     @property           sysname = NULL, /* The property to change */
  11928.     @value              nvarchar(255) = NULL,    /* The new property value */
  11929.     @force_reinit_subscription bit = 0    /* Force reinit subscription */
  11930.     ) AS
  11931.  
  11932.     SET NOCOUNT ON
  11933.  
  11934.     /*
  11935.     ** Declarations.
  11936.     */
  11937.     declare @subscriber_bit         smallint
  11938.     declare @subscriber_srvid       int
  11939.     declare @publisher_srvid        int
  11940.     declare @retcode                int
  11941.     declare @pubid                  uniqueidentifier
  11942.     declare @subid                  uniqueidentifier
  11943.     declare @partnerid              uniqueidentifier
  11944.     declare @sync_typeid            tinyint
  11945.     declare @nosync                 tinyint
  11946.     declare @automatic              tinyint
  11947.      
  11948.     declare @artid                  uniqueidentifier
  11949.     declare @schematype             int
  11950.     declare @schemaversion          int
  11951.     declare @schemaguid             uniqueidentifier
  11952.     declare @db_name                sysname
  11953.     declare @subscriber_type        int
  11954.     declare @schematext             nvarchar(2000)
  11955.     declare @publisher              sysname
  11956.     declare @publisher_db           sysname
  11957.     declare @use_interactive_bit    bit 
  11958.     declare @enabled_for_syncmgr    int
  11959.     declare @regkey                    nvarchar(1000)
  11960.     declare @snapshot_ready            int
  11961.      
  11962.  
  11963.     /*
  11964.     ** Initializations.
  11965.     */
  11966.     SET @nosync         = 2     /* Const: synchronization type 'none' */
  11967.     SET @automatic      = 1     /* Const: synchronization type 'automatic' */
  11968.     set @publisher      = @@SERVERNAME
  11969.     set @publisher_db   = DB_NAME()
  11970.  
  11971.     /*
  11972.     ** Security Check.
  11973.     */
  11974.     BEGIN
  11975.         exec @retcode = dbo.sp_MSreplcheck_subscribe
  11976.         if @@ERROR <> 0 or @retcode <> 0
  11977.             return(1)
  11978.     END
  11979.  
  11980.  
  11981.     /*
  11982.     **  Check to see if current database is doing publishing/subscribing
  11983.     */
  11984.     IF not exists (select name from sysobjects where name='sysmergesubscriptions')
  11985.         BEGIN
  11986.             RAISERROR (14055, 16, -1)
  11987.             RETURN (1)
  11988.         END
  11989.  
  11990.     /*
  11991.     ** Parameter Check:  @property.
  11992.     ** If the @property parameter is NULL, print the options.
  11993.     */
  11994.  
  11995.     IF @property IS NULL
  11996.         BEGIN
  11997.             CREATE TABLE #tab1 (properties sysname collate database_default)
  11998.             INSERT INTO #tab1 VALUES ('sync_type')
  11999.             INSERT INTO #tab1 VALUES ('priority')
  12000.             INSERT INTO #tab1 VALUES ('description') 
  12001.             INSERT INTO #tab1 VALUES ('use_interactive_resolver') 
  12002.             select * FROM #tab1
  12003.             RETURN (0)
  12004.         END
  12005.  
  12006.     /*
  12007.     ** Parameter Check:  @publication.
  12008.     ** Make sure that the publication exists.
  12009.     */
  12010.  
  12011.     IF @publication IS NULL
  12012.         BEGIN
  12013.             RAISERROR (14043, 16, -1, '@publication')
  12014.             RETURN (1)
  12015.         END
  12016.  
  12017.     select @pubid = pubid, @snapshot_ready=snapshot_ready FROM sysmergepublications 
  12018.         WHERE name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  12019.     IF @pubid IS NULL
  12020.         BEGIN
  12021.             RAISERROR (20026, 11, -1, @publication)
  12022.             RETURN (1)
  12023.         END
  12024.  
  12025.     /*
  12026.     ** Validate that the publisher is a valid server
  12027.     */
  12028.     select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
  12029.     IF @publisher_srvid IS NULL
  12030.         BEGIN
  12031.             RAISERROR (14010, 16, -1)
  12032.             RETURN (1)
  12033.         END
  12034.  
  12035.     /*
  12036.     ** Parameter Check:  @subscriber.
  12037.     ** Check to make sure we have a valid subscriber.
  12038.     */
  12039.     IF @subscriber IS NULL
  12040.         BEGIN
  12041.             RAISERROR (14043, 16, -1, '@subscriber')
  12042.             RETURN (1)
  12043.         END
  12044.     /*
  12045.     ** Validate that the subscriber is a valid server
  12046.     */
  12047.     select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
  12048.     IF @subscriber_srvid IS NULL
  12049.         BEGIN
  12050.             RAISERROR (14010, 16, -1)
  12051.             RETURN (1)
  12052.         END
  12053.  
  12054.     /*
  12055.     ** Check to see if you have a local / global subscription on this publication
  12056.     */
  12057.     set @subid = NULL
  12058.     select @subid = subs1.subid, 
  12059.      
  12060.     @pubid = pubs.pubid, /* identified from publication name */
  12061.     @subscriber_type=subs1.subscriber_type,
  12062.      
  12063.         @partnerid = subs2.subid from
  12064.         sysmergesubscriptions   subs1,
  12065.         sysmergesubscriptions   subs2,
  12066.         sysmergepublications    pubs
  12067.         where subs1.srvid = @subscriber_srvid
  12068.             and subs1.db_name = @subscriber_db
  12069.             and subs2.srvid = @publisher_srvid
  12070.             and subs2.db_name = @publisher_db
  12071.             and subs1.pubid = subs2.subid
  12072.             and subs2.pubid = pubs.pubid
  12073.             and pubs.name = @publication 
  12074.             and UPPER(pubs.publisher)=UPPER(@@servername) 
  12075.             and pubs.publisher_db=db_name()
  12076.  
  12077.     if @subid IS NULL 
  12078.         begin
  12079.             RAISERROR (14050, 11, -1)
  12080.             RETURN(1)
  12081.         end                 
  12082.  
  12083.     /*
  12084.     ** Parameter Check:  @property.
  12085.     ** Check to make sure that @property is a valid property in
  12086.     ** sysarticles.
  12087.     */
  12088.  
  12089.     
  12090.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('sync_type', 'priority', 'description', 'use_interactive_resolver')
  12091.         BEGIN
  12092.             RAISERROR (20078, 16, -1)
  12093.             RETURN (1)
  12094.         END
  12095.  
  12096.  
  12097.     BEGIN TRANSACTION change_subscription
  12098.     save TRAN change_subscription
  12099.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'use_interactive_resolver'
  12100.         BEGIN
  12101.  
  12102.             /* Check to make sure that we have a true/false. */
  12103.  
  12104.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  12105.                 BEGIN
  12106.                     RAISERROR (14148, 16, -1, 'use_interactive_resolver')
  12107.                     goto UNDO    
  12108.                 END
  12109.  
  12110.             /* Determine the bit value. */
  12111.  
  12112.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  12113.                 SET @use_interactive_bit = 1
  12114.             ELSE
  12115.                 SET @use_interactive_bit = 0
  12116.     
  12117.             /* Update the subscription with the new 'use_interactive' value. */
  12118.  
  12119.             UPDATE sysmergesubscriptions
  12120.                    SET use_interactive_resolver = @use_interactive_bit
  12121.                  WHERE subid = @subid
  12122.             IF @@ERROR <> 0
  12123.                 BEGIN
  12124.                     RAISERROR (14053, 16, -1)
  12125.                     goto UNDO
  12126.                 END
  12127.  
  12128.             /* If the subscription is enable for Sync Manager, then update the reg value */
  12129.             exec sp_MSsubscription_enabled_for_syncmgr
  12130.                 @publisher, @publisher_db, @publication, @subscriber, @subscriber_db, 
  12131.                 @enabled_for_syncmgr OUT, @regkey OUT
  12132.             IF @@ERROR <> 0
  12133.                 BEGIN
  12134.                     RAISERROR (14053, 16, -1)
  12135.                     goto UNDO
  12136.                 END
  12137.             if @enabled_for_syncmgr = 1
  12138.                 begin
  12139.                     EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
  12140.                                            @regkey,
  12141.                                            'UseInteractiveResolver',
  12142.                                            'REG_DWORD',
  12143.                                             @use_interactive_bit
  12144.                     if @retcode <> 0 OR @@ERROR <> 0
  12145.                         BEGIN
  12146.                             RAISERROR (14053, 16, -1)
  12147.                             goto UNDO
  12148.                         END
  12149.                 end
  12150.         END
  12151.  
  12152.     /*
  12153.     ** Change the property.
  12154.     */
  12155.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'sync_type'
  12156.         BEGIN 
  12157.             /*
  12158.             ** Check to make sure that we have a valid sync_type.
  12159.             */
  12160.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('automatic', 'none')
  12161.                 BEGIN
  12162.                     RAISERROR (14052, 16, -1)
  12163.                     goto UNDO
  12164.                 END
  12165.  
  12166.             /*
  12167.             ** Determine the integer value for the sync_type.
  12168.             */
  12169.  
  12170.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'automatic'
  12171.                 SET @sync_typeid = @automatic
  12172.             ELSE
  12173.             BEGIN
  12174.  
  12175.             /*
  12176.             **  If current publication contains an article without rowguidcol, do not allow no-sync subscription
  12177.             */    
  12178.             if exists (select * from sysmergearticles a where pubid = @pubid and 
  12179.                     not exists (select * from syscolumns c where c.id=a.objid and columnproperty (c.id, c.name, 'isrowguidcol')=1))
  12180.                 begin
  12181.                     Raiserror(20086, 16, -1, @publication)
  12182.                     goto UNDO
  12183.                 end
  12184.                 else 
  12185.                     SET @sync_typeid = @nosync
  12186.             END
  12187.  
  12188.             /*
  12189.             ** Update the subscription with the new sync_type.
  12190.             */
  12191.  
  12192.             UPDATE sysmergesubscriptions
  12193.                 SET sync_type = @sync_typeid
  12194.                 WHERE subid = @subid
  12195.             IF @@ERROR <> 0
  12196.                 BEGIN
  12197.                     RAISERROR (14053, 16, -1)
  12198.                     goto UNDO
  12199.                 END
  12200.  
  12201.             if @snapshot_ready>0
  12202.             begin
  12203.                 --if there is one article in this publication with pre_command of other than 'drop',
  12204.                 --do not allow changing subscription property.
  12205.                 if exists (select * from sysmergearticles where pubid=@pubid and pre_creation_command<>1)
  12206.                     begin
  12207.                         RAISERROR (21420, 16, -1, @property)
  12208.                         goto UNDO                
  12209.                     end
  12210.                 /*
  12211.                 ** make sure we know we really want to do this.
  12212.                 */
  12213.                 if @force_reinit_subscription = 0
  12214.                     begin
  12215.                         raiserror(20608, 16, -1)
  12216.                         goto UNDO
  12217.                     end
  12218.                 exec @retcode=sp_MSreinitmergepublication @publication
  12219.                 if @@ERROR<>0 or @retcode<>0
  12220.                     GOTO UNDO 
  12221.             end
  12222.         END
  12223.         
  12224.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'description'
  12225.         BEGIN
  12226.         UPDATE sysmergesubscriptions
  12227.                 SET description = @value
  12228.                 WHERE subid = @subid
  12229.             IF @@ERROR <> 0
  12230.                 BEGIN
  12231.                     RAISERROR (14053, 16, -1) 
  12232.               
  12233.                     goto UNDO
  12234.                 END
  12235.  
  12236.         END
  12237.         
  12238.      
  12239.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'priority'
  12240.     BEGIN
  12241.  
  12242.     select @db_name = db_name from sysmergesubscriptions
  12243.         where (pubid=@pubid) and (subid=@pubid)
  12244.         IF @db_name <> db_name()
  12245.         BEGIN
  12246.             RAISERROR (20047, 16, -1)
  12247.             goto UNDO
  12248.         END  
  12249.  
  12250.     /* Only the original publisher can change priority of a global subscriptions */
  12251.  
  12252.         IF @subscriber_type<>1  
  12253.             BEGIN
  12254.                 RAISERROR (20044, 16, -1)  /* Local subscriber does not have priority*/
  12255.                 goto UNDO
  12256.             END
  12257.  
  12258.         IF convert(real, @value)>100.0
  12259.             BEGIN
  12260.                 RAISERROR (20049, 16, -1)  /* Don't accept priority greater than 100 */
  12261.                 goto UNDO
  12262.             END
  12263.         
  12264.         exec dbo.sp_MSchange_priority @subid,  @value
  12265.         if @@ERROR<>0 goto UNDO
  12266.            /* Insert the sp_MSchange_priority schema change only if the publication's snapshot is ready */
  12267.         if (@snapshot_ready > 0)
  12268.             begin
  12269.                 select @schemaversion = schemaversion from sysmergeschemachange
  12270.                 if (@schemaversion is NULL)
  12271.                 set @schemaversion = 1
  12272.                 else
  12273.                     select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
  12274.                     
  12275.                  
  12276.                 set @schemaguid = newid()
  12277.                 set @artid = newid()
  12278.                 set @schematype = 8 /* change priority */
  12279.                 select @schematext = 'exec dbo.sp_MSchange_priority '+ '''' + convert(nchar(36),@subid) + '''' + ',' + '''' + @value + '''' 
  12280.                 exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
  12281.                 if @@ERROR<>0 or @retcode<>0 goto UNDO
  12282.             end                    
  12283.     END
  12284.  
  12285.     COMMIT TRANSACTION
  12286.  
  12287.     /*
  12288.     ** Return succeed. It is not an error message.
  12289.     */
  12290.  
  12291.     RAISERROR (14054, 10, -1)
  12292.     RETURN (0)
  12293. UNDO:
  12294.     if @@TRANCOUNT > 0
  12295.     begin
  12296.         ROLLBACK TRANSACTION change_subscription
  12297.         COMMIT TRANSACTION
  12298.     end
  12299.     return (1)
  12300. go
  12301.  
  12302. exec dbo.sp_MS_marksystemobject sp_changemergesubscription 
  12303. go
  12304.  
  12305. grant execute on dbo.sp_changemergesubscription to public
  12306. go
  12307.  
  12308. raiserror('Creating procedure sp_helpmergesubscription', 0,1)
  12309. GO
  12310.  
  12311. CREATE PROCEDURE sp_helpmergesubscription(
  12312.     @publication            sysname = '%',      /* Publication name */
  12313.     @subscriber             sysname = '%',      /* Subscriber server */
  12314.     @subscriber_db          sysname = '%',      /* Subscription database */
  12315.     @publisher              sysname = '%',      /* Publisher server */
  12316.     @publisher_db           sysname = '%',      /* Publisher database */
  12317.     @subscription_type      nvarchar(15) = 'both', /* Subscription type - push or pull */ 
  12318.     @found int = NULL OUTPUT
  12319.     )AS
  12320.  
  12321.     SET NOCOUNT ON
  12322.  
  12323.     /*
  12324.     ** Declarations.
  12325.     */
  12326.  
  12327.     declare @db                 sysname
  12328.     declare @retcode            int
  12329.     declare @subscriber_bit     smallint
  12330.     declare @srvid              int
  12331.     declare @pubid              uniqueidentifier
  12332.     declare @subid              uniqueidentifier
  12333.     declare @partnerid          uniqueidentifier
  12334.     declare @cursor_open        int
  12335.     declare @no_row             bit
  12336.     declare @subscription_type_id int
  12337.  
  12338.     declare @distributor    sysname
  12339.     declare @distributiondb sysname
  12340.     declare @distproc       nvarchar(300)
  12341.     declare @dbname         sysname
  12342.  
  12343.     select @distributor = null
  12344.     select @distributiondb = null
  12345.     select @distproc = null
  12346.     select @dbname = null    
  12347.  
  12348.     /*
  12349.     ** Initializations.
  12350.     */
  12351.     set @subscriber_bit     = 4
  12352.     set @cursor_open        = 0                 
  12353.  
  12354.     /*
  12355.     ** Initializations of @now_row.
  12356.     */
  12357.     IF @found is NULL
  12358.     BEGIN
  12359.         SELECT @no_row=0
  12360.     END
  12361.     ELSE
  12362.     BEGIN
  12363.         SELECT @no_row=1
  12364.     END
  12365.  
  12366.     select @db=db_name() -- so that it can appear in dynamic query
  12367.  
  12368.     /*
  12369.     **  Calling sp_help* is all right whether current database is enabled for pub/sub or not
  12370.     */
  12371.  
  12372.     IF not exists (select * from sysobjects where name='sysmergesubscriptions')
  12373.         RETURN (0)
  12374.     
  12375.     /* Security check */
  12376.     EXEC @retcode = dbo.sp_MSreplcheck_pull @publication = @publication, 
  12377.         @raise_fatal_error = 0
  12378.     if @@ERROR <> 0 or @retcode <> 0
  12379.         return(1)
  12380.  
  12381.     /*
  12382.     ** Parameter Check: @subscription_type.
  12383.     ** Set subscription_typeid based on the @subscription_type specified.
  12384.     **
  12385.     **   subscription_type    subscription_type
  12386.     **   =================    ===============
  12387.     **             0            push
  12388.     **             1            pull
  12389.     **            2         both
  12390.     */
  12391.     if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('push', 'pull', 'both')
  12392.         BEGIN
  12393.             RAISERROR (20079, 16, -1)
  12394.             RETURN (1)
  12395.         END
  12396.     IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'both'
  12397.         set @subscription_type_id = 2
  12398.     else IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push'
  12399.         set @subscription_type_id = 0
  12400.     else 
  12401.         set @subscription_type_id = 1
  12402.  
  12403.     /*
  12404.     ** Parameter Check: @publisher
  12405.     ** Check to make sure that the publisher is defined
  12406.     */
  12407.     IF @publisher <> '%'
  12408.     BEGIN
  12409.         EXECUTE @retcode = dbo.sp_validname @publisher
  12410.         IF @@ERROR <> 0 OR @retcode <> 0
  12411.             RETURN (1)
  12412.     END
  12413.  
  12414.     /*
  12415.     ** Parameter Check:  @subscriber.
  12416.     ** If remote server, limit the view to the remote server's subscriptions.
  12417.     ** Make sure that the name isn't NULL.
  12418.     */
  12419.     if @subscriber IS NULL
  12420.         BEGIN
  12421.             RAISERROR (14043, 16, -1, '@subscriber')
  12422.             RETURN (1)
  12423.         END
  12424.  
  12425.     /*
  12426.     ** Parameter Check:  @subscriber.
  12427.     ** Check if remote server is defined as a subscription server, and
  12428.     ** that the name conforms to the rules for identifiers.
  12429.     */
  12430.  
  12431.     if @subscriber <> '%'
  12432.         BEGIN
  12433.             EXECUTE @retcode = dbo.sp_validname @subscriber
  12434.  
  12435.             if @retcode <> 0 OR @@ERROR <> 0
  12436.                 RETURN (1)
  12437.  
  12438.             if NOT EXISTS (select *
  12439.                             FROM master..sysservers
  12440.                             WHERE UPPER(srvname) = UPPER(@subscriber) collate database_default
  12441.                             AND (srvstatus & @subscriber_bit) <> 0)
  12442.                 BEGIN
  12443.                     --RAISERROR (14010, 16, -1)
  12444.                     RETURN (1)
  12445.                 END
  12446.         END
  12447.  
  12448.     /*
  12449.     ** Parameter Check:  @publication.
  12450.     ** If the publication name is specified, check to make sure that it
  12451.     ** conforms to the rules for identifiers and that the publication
  12452.     ** actually exists.  Disallow NULL.
  12453.     */
  12454.     if @publication IS NULL
  12455.         BEGIN
  12456.             RAISERROR (14043, 16, -1, '@publication')
  12457.             RETURN (1)
  12458.         END
  12459.  
  12460.     /*
  12461.     ** Get subscriptions
  12462.     */
  12463.     if @publication <>'%'
  12464.     begin
  12465.         execute @retcode = dbo.sp_MSsubsetpublication @publication
  12466.         if @@ERROR <> 0 or @retcode<>0
  12467.                 Return (1)
  12468.     end
  12469.     
  12470.     create table #helpsubscription
  12471.                 (
  12472.                     publication             sysname     collate database_default not null,
  12473.                     publisher               sysname     collate database_default not null,
  12474.                     publisher_db            sysname     collate database_default not null,
  12475.                     subscriber              sysname     collate database_default not null,
  12476.                     subscriber_db           sysname     collate database_default not null,
  12477.                     status                  int         NOT NULL,
  12478.                     subscriber_type         int         NOT NULL,
  12479.                     subscription_type       int         NOT NULL,
  12480.                     priority                float(8)    NOT NULL,
  12481.                     sync_type               tinyint     NOT NULL,
  12482.                     description             nvarchar(255) collate database_default null,
  12483.                     merge_jobid             binary(16)  NULL,
  12484.                     full_publication        tinyint     NULL,
  12485.                     use_interactive_resolver     int        NULL
  12486.                 )
  12487.  
  12488.  
  12489.     /* 
  12490.     ** Performance Optimization: Eliminate the 'LIKE' clause for publication name.
  12491.     **                           Empirical evidence shows almost 50% speed improvement when
  12492.     **                           opening the cursor if publication name is provided.
  12493.     */
  12494.     IF (@publication <> '%')
  12495.         insert into #helpsubscription select distinct pubs.name, servers2.srvname, subs2.db_name, servers1.srvname, subs1.db_name, 
  12496.                         subs1.status, subs1.subscriber_type, subs1.subscription_type, subs1.priority, 
  12497.                         subs1.sync_type, subs1.description, replinfo.merge_jobid, pubs.publication_type,
  12498.                         subs1.use_interactive_resolver
  12499.  
  12500.                 FROM  sysmergesubscriptions     subs1,
  12501.                       sysmergesubscriptions     subs2,
  12502.                       MSmerge_replinfo      replinfo,
  12503.                       master..sysservers        servers1,
  12504.                       master..sysservers        servers2,
  12505.                       sysmergepublications  pubs
  12506.                     where subs1.subid <> subs2.subid 
  12507.                         and subs1.status <> 2 
  12508.                         and subs2.subid = subs1.partnerid
  12509.                         and pubs.pubid = subs1.pubid
  12510.                         and pubs.pubid = subs2.pubid
  12511.                         and servers1.srvid = subs1.srvid
  12512.                         and servers2.srvid = subs2.srvid
  12513.                         and pubs.name =  @publication 
  12514.                         and replinfo.repid = subs1.subid
  12515.                         and (suser_sname(suser_sid()) = subs1.login_name OR is_member('db_owner')=1 OR is_srvrolemember('sysadmin') = 1)
  12516.                         and ((@subscriber_db = N'%') or (subs1.db_name = @subscriber_db collate database_default))
  12517.                         and ((@publisher_db = N'%') or (subs2.db_name = @publisher_db collate database_default))
  12518.                         and ((@subscriber = N'%') or (UPPER(servers1.srvname) = UPPER(@subscriber) collate database_default)) 
  12519.                         and ((@publisher = N'%') or (UPPER(servers2.srvname) = UPPER(@publisher) collate database_default))
  12520.                         and (subs1.subscription_type = @subscription_type_id or @subscription_type_id = 2)
  12521.     ELSE
  12522.         insert into #helpsubscription select distinct pubs.name, servers2.srvname, subs2.db_name, servers1.srvname, subs1.db_name, 
  12523.                         subs1.status, subs1.subscriber_type, subs1.subscription_type, subs1.priority, 
  12524.                         subs1.sync_type, subs1.description, replinfo.merge_jobid, pubs.publication_type,
  12525.                         subs1.use_interactive_resolver
  12526.  
  12527.                 FROM  sysmergesubscriptions     subs1,
  12528.                       sysmergesubscriptions     subs2,
  12529.                       MSmerge_replinfo      replinfo,
  12530.                       master..sysservers        servers1,
  12531.                       master..sysservers        servers2,
  12532.                       sysmergepublications  pubs
  12533.                     where subs1.subid <> subs2.subid 
  12534.                         and subs1.status <> 2 
  12535.                         and subs2.subid = subs1.partnerid
  12536.                         and pubs.pubid = subs1.pubid
  12537.                         and pubs.pubid = subs2.pubid
  12538.                         and servers1.srvid = subs1.srvid
  12539.                         and servers2.srvid = subs2.srvid
  12540.                         and replinfo.repid = subs1.subid
  12541.                         and (suser_sname(suser_sid()) = subs1.login_name OR is_member('db_owner')=1 OR is_srvrolemember('sysadmin') = 1)
  12542.                         and ((@subscriber_db = N'%') or (subs1.db_name = @subscriber_db collate database_default))
  12543.                         and ((@publisher_db = N'%') or (subs2.db_name = @publisher_db collate database_default)) 
  12544.                         and ((@subscriber = N'%') or (UPPER(servers1.srvname) = UPPER(@subscriber) collate database_default)) 
  12545.                         and ((@publisher = N'%') or (UPPER(servers2.srvname) = UPPER(@publisher) collate database_default))
  12546.                         and (subs1.subscription_type = @subscription_type_id or @subscription_type_id = 2)
  12547.         
  12548.  
  12549.     if exists (select * from #helpsubscription)
  12550.         select @found = 1
  12551.     else
  12552.         select @found = 0 
  12553.         
  12554.     if @no_row = 1
  12555.         goto DONE
  12556.  
  12557.     CREATE TABLE #merge_agent_properties
  12558.     (
  12559.         job_id                VARBINARY(16) NOT NULL,
  12560.         offload_enabled       bit NULL,
  12561.         offload_server        sysname collate database_default null
  12562.     )
  12563.  
  12564.     EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
  12565.                                            @distribdb = @distributiondb OUTPUT
  12566.     IF @retcode <> 0
  12567.         GOTO DONE
  12568.  
  12569.     SELECT @distributor = RTRIM(@distributor)
  12570.  
  12571.     -- Get distribution agent properties 
  12572.     IF LOWER(@@SERVERNAME) <> LOWER(@distributor)
  12573.     BEGIN
  12574.         SELECT @distproc = @distributor + '.' + @distributiondb + 
  12575.                            '.dbo.sp_MSenum_merge_agent_properties'
  12576.     END    
  12577.     ELSE
  12578.     BEGIN
  12579.         SELECT @distproc = @distributiondb + 
  12580.                            '.dbo.sp_MSenum_merge_agent_properties'
  12581.     END
  12582.  
  12583.     SELECT @dbname = db_name()
  12584.  
  12585.     INSERT INTO #merge_agent_properties
  12586.       EXEC @retcode = @distproc @publisher = @@SERVERNAME, 
  12587.                                 @publisher_db = @dbname, 
  12588.                                 @publication = @publication            
  12589.  
  12590.     IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push' or LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'both'
  12591.         begin
  12592.             select 'subscription_name'  = subscriber + ':' + subscriber_db,
  12593.                 hs.publication, hs.publisher, hs.publisher_db, 
  12594.                 hs.subscriber, hs.subscriber_db, hs.status, hs.subscriber_type,
  12595.                 hs.subscription_type, hs.priority, hs.sync_type, hs.description,
  12596.                 hs.merge_jobid, hs.full_publication,
  12597.                 ap.offload_enabled, ap.offload_server,
  12598.                 hs.use_interactive_resolver
  12599.                 from #helpsubscription hs
  12600.                 left outer join #merge_agent_properties ap
  12601.                 on hs.merge_jobid = ap.job_id
  12602.                 order by hs.publisher, hs.publisher_db, hs.publication, hs.subscriber, hs.subscriber_db
  12603.         end
  12604.     else 
  12605.         begin
  12606.             select 'subscription_name' = hs.publisher + ':' + hs.publisher_db + ':' + hs.publication, 
  12607.                 hs.publication, hs.publisher, hs.publisher_db, 
  12608.                 hs.subscriber, hs.subscriber_db, hs.status, hs.subscriber_type,
  12609.                 hs.subscription_type, hs.priority, hs.sync_type, hs.description,
  12610.                 hs.merge_jobid, hs.full_publication,
  12611.                 ap.offload_enabled, ap.offload_server,                 
  12612.                 hs.use_interactive_resolver
  12613.                 from #helpsubscription hs
  12614.                 left outer join #merge_agent_properties ap
  12615.                 on hs.merge_jobid = ap.job_id
  12616.                 order by hs.publisher, hs.publisher_db, hs.publication, hs.subscriber, hs.subscriber_db
  12617.         end
  12618.  
  12619.     drop table #merge_agent_properties
  12620.     select @retcode = 0
  12621. DONE:
  12622.     if (@cursor_open = 1)
  12623.         begin
  12624.             close #cursor
  12625.             deallocate #cursor
  12626.         end         
  12627.     drop table #helpsubscription
  12628.     return @retcode 
  12629. go
  12630. exec dbo.sp_MS_marksystemobject sp_helpmergesubscription
  12631. go
  12632.  
  12633. grant execute on dbo.sp_helpmergesubscription to public
  12634. go
  12635.  
  12636. raiserror('Creating procedure sp_dropmergesubscription', 0,1)
  12637. GO
  12638. CREATE PROCEDURE sp_dropmergesubscription(
  12639.     @publication        sysname = NULL,             /* Publication name */
  12640.     @subscriber         sysname = NULL,             /* Subscriber server */
  12641.     @subscriber_db      sysname = NULL,             /* Subscription database */
  12642.     @subscription_type  nvarchar(15) = 'both',          /* Subscription type - push, pull, both */ 
  12643.     @ignore_distributor bit = 0,
  12644.     @reserved             bit = 0
  12645.     )AS
  12646.  
  12647.     SET NOCOUNT ON
  12648.  
  12649.     /*
  12650.     ** Declarations.
  12651.     */
  12652.     declare @retcode                int
  12653.     declare @subscriber_bit         smallint
  12654.     declare @subscriber_type        smallint
  12655.     declare @subscriber_srvid       int
  12656.     declare @publisher_srvid        int
  12657.     declare @pubid                  uniqueidentifier
  12658.     declare @subid                  uniqueidentifier
  12659.     declare @partnerid              uniqueidentifier
  12660.     declare @subscription_type_id   int   
  12661.     declare @found_subscription     int   
  12662.     declare @local_server           sysname
  12663.     declare @local_db               sysname
  12664.     declare @cmd                    nvarchar(290)
  12665.     declare @distributor            sysname
  12666.     declare @distribdb              sysname
  12667.     declare @distproc               nvarchar(300)
  12668.     declare @pubidstr               nvarchar(38)
  12669.     declare @publisher              sysname
  12670.     declare @publisher_db           sysname
  12671.  
  12672.     declare @implicit_transaction    int
  12673.     declare @close_cursor_at_commit int
  12674.  
  12675.     select @close_cursor_at_commit = 0
  12676.     select @implicit_transaction = 0
  12677.  
  12678.     -- Security check
  12679.     if 1 <> is_member('db_owner')
  12680.     begin
  12681.         RAISERROR (15247, 11, -1)
  12682.         return 1
  12683.     end
  12684.  
  12685.     /*
  12686.     ** Save setting values first before changing them
  12687.     */
  12688.     IF (@reserved = 0)
  12689.     BEGIN
  12690.         SELECT @implicit_transaction = @@options & 2
  12691.         SELECT @close_cursor_at_commit = @@options & 4
  12692.         SET IMPLICIT_TRANSACTIONS OFF
  12693.         SET CURSOR_CLOSE_ON_COMMIT OFF
  12694.     END
  12695.  
  12696.      /*
  12697.     ** Initializations.
  12698.     */
  12699.     set @subscriber_bit     = 4
  12700.     set @subscription_type_id = -1
  12701.     set @found_subscription = 0                     
  12702.     set @local_db           = DB_NAME()
  12703.     set @local_server       = @@SERVERNAME
  12704.     set @publisher          = @@SERVERNAME
  12705.     set @publisher_db       = DB_NAME()
  12706.  
  12707.     /*
  12708.     **  Check to see if current database is enabled for publishing/subscribing
  12709.     */
  12710.     IF not exists (select name from sysobjects where name='sysmergesubscriptions')
  12711.         BEGIN
  12712.             RAISERROR (14055, 16, -1)
  12713.             RETURN (1)
  12714.         END
  12715.  
  12716.     /*
  12717.     ** Parameter Check: @subscription_type.
  12718.     ** Set subscription_typeid based on the @subscription_type specified.
  12719.     **
  12720.     **   subscription_type    subscription_type
  12721.     **   =================    ===============
  12722.     **             0            push
  12723.     **             1            pull
  12724.     */
  12725.     if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('both', 'push', 'pull')
  12726.         BEGIN
  12727.             RAISERROR (14128, 16, -1)
  12728.             RETURN (1)
  12729.         END
  12730.     IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'both'
  12731.         begin
  12732.             EXECUTE @retcode = dbo.sp_dropmergesubscription @publication = @publication,
  12733.                             @subscriber = @subscriber,
  12734.                             @subscriber_db = @subscriber_db,
  12735.                             @subscription_type = 'push',
  12736.                             @ignore_distributor = @ignore_distributor,
  12737.                             @reserved = 1
  12738.             if @retcode<>0 or @@ERROR<>0
  12739.                 return (1)
  12740.             EXECUTE @retcode = dbo.sp_dropmergesubscription @publication = @publication,
  12741.                             @subscriber = @subscriber,
  12742.                             @subscriber_db = @subscriber_db,
  12743.                             @subscription_type = 'pull',
  12744.                             @ignore_distributor = @ignore_distributor,
  12745.                             @reserved = 1
  12746.             if @retcode<>0 or @@ERROR<>0
  12747.                 return (1)
  12748.             return (0)
  12749.         end 
  12750.     IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push'
  12751.         set @subscription_type_id = 0
  12752.     else 
  12753.         set @subscription_type_id = 1
  12754.  
  12755.     /*
  12756.     ** Parameter validation (different for push and pull modes)
  12757.     */
  12758.  
  12759.     IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push'
  12760.         begin
  12761.             /*
  12762.             ** Assign parameter values appropriately
  12763.             */
  12764.             if @publisher IS NULL
  12765.                 set @publisher = @@SERVERNAME
  12766.             if (@publisher_db IS NULL)
  12767.                 set @publisher_db = DB_NAME()
  12768.  
  12769.             /*
  12770.             ** Parameter Check: @subscriber
  12771.             ** Check to make sure that the subscriber is defined
  12772.             */
  12773.             IF @subscriber IS NULL
  12774.             BEGIN
  12775.                 RAISERROR (14043, 16, -1, '@subscriber')
  12776.                 RETURN (1)
  12777.             END
  12778.  
  12779.             /*
  12780.             ** Parameter Check: @subscriber_db
  12781.             */
  12782.             IF @subscriber_db IS NULL
  12783.             BEGIN
  12784.                 select @subscriber_db = 'all'
  12785.             END
  12786.                 
  12787.         end
  12788.     else
  12789.         begin
  12790.             /*
  12791.             ** Assign parameter values appropriately
  12792.             */
  12793.             if @subscriber IS NULL
  12794.                 set @subscriber = @@SERVERNAME
  12795.             if @subscriber_db IS NULL
  12796.                 set @subscriber_db = DB_NAME()
  12797.  
  12798.             /*
  12799.             ** Parameter Check: @publisher
  12800.             ** Check to make sure that the publisher is defined
  12801.             */
  12802.             IF @publisher IS NULL
  12803.             BEGIN
  12804.                 RAISERROR (14043, 16, -1, '@publisher')
  12805.                 RETURN (1)
  12806.             END
  12807.  
  12808.             EXECUTE @retcode = dbo.sp_validname @publisher
  12809.             IF @@ERROR <> 0 OR @retcode <> 0
  12810.                RETURN (1)
  12811.  
  12812.             /*
  12813.             ** Parameter Check: @publisher_db
  12814.             */
  12815.             IF @publisher_db IS NULL
  12816.             BEGIN
  12817.                 RAISERROR (14043, 16, -1, '@publisher_db')
  12818.                 RETURN (1)
  12819.             END
  12820.  
  12821.         end     
  12822.  
  12823.     /*
  12824.     ** Parameter Check:  @publication.
  12825.     ** If the publication name is specified, check to make sure that it
  12826.     ** conforms to the rules for identifiers and that the publication
  12827.     ** actually exists.  Disallow NULL.
  12828.     */
  12829.     if @publication IS NULL
  12830.         BEGIN
  12831.             RAISERROR (14043, 16, -1, '@publication')
  12832.             RETURN (1)
  12833.         END
  12834.  
  12835.     IF LOWER(@publication) = 'all'
  12836.         BEGIN
  12837.             declare hC1 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT name FROM sysmergepublications 
  12838.                 where UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name() 
  12839.                 FOR READ ONLY
  12840.             
  12841.             OPEN hC1
  12842.             FETCH hC1 INTO @publication
  12843.             WHILE (@@fetch_status <> -1)
  12844.                 BEGIN
  12845.                     EXECUTE dbo.sp_dropmergesubscription @publication = @publication,
  12846.                                                 @subscriber = @subscriber,
  12847.                                                 @subscriber_db = @subscriber_db,
  12848.                                                 @subscription_type = @subscription_type,
  12849.                                                 @ignore_distributor = @ignore_distributor,
  12850.                                                 @reserved = 1
  12851.                     FETCH hC1 INTO @publication
  12852.                 END
  12853.             CLOSE hC1
  12854.             DEALLOCATE hC1
  12855.             RETURN (0)
  12856.         END
  12857.         
  12858.     if NOT EXISTS (select * FROM sysmergepublications 
  12859.         WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name())
  12860.         BEGIN
  12861.             RAISERROR (20026, 16, -1, @publication)
  12862.             RETURN (1)
  12863.         END
  12864.     select @pubid = pubid from sysmergepublications 
  12865.         where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  12866.     set @pubidstr = '''' + convert(nchar(36), @pubid) + ''''
  12867.     if @pubid is null
  12868.         BEGIN
  12869.             RAISERROR (20026, 16, -1, @publication)
  12870.             RETURN (1)
  12871.         END
  12872.  
  12873.        
  12874.     IF LOWER(@subscriber) = 'all'
  12875.         BEGIN
  12876.             declare hC2 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT srvname 
  12877.             FROM master..sysservers 
  12878.             WHERE (srvstatus & 4 <> 0) FOR READ ONLY
  12879.     
  12880.             OPEN hC2
  12881.             FETCH hC2 INTO @subscriber
  12882.             WHILE (@@fetch_status <> -1)
  12883.                 BEGIN
  12884.                     EXECUTE dbo.sp_dropmergesubscription @publication = @publication,
  12885.                                                 @subscriber = @subscriber,
  12886.                                                 @subscriber_db = @subscriber_db,
  12887.                                                 @subscription_type = @subscription_type,
  12888.                                                 @ignore_distributor = @ignore_distributor,
  12889.                                                 @reserved = 1
  12890.                     FETCH hC2 INTO @subscriber
  12891.                 END
  12892.             CLOSE hC2
  12893.             DEALLOCATE hC2
  12894.             RETURN (0)
  12895.         END
  12896.  
  12897.     /*
  12898.     ** Validate that the subscriber is a valid server
  12899.     */
  12900.     select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
  12901.     IF @subscriber_srvid IS NULL
  12902.         BEGIN
  12903.             --RAISERROR (14010, 16, -1)
  12904.             RETURN (1)
  12905.         END
  12906.  
  12907.     /*
  12908.     ** NOTE: remove this batch
  12909.     */
  12910.     IF LOWER(@subscriber_db) = 'all'
  12911.         BEGIN
  12912.                 declare hC3 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT db_name FROM sysmergesubscriptions
  12913.                 WHERE srvid =  @subscriber_srvid 
  12914.                     AND subid <> pubid 
  12915.                     AND sysmergesubscriptions.pubid = @pubid
  12916.                     AND sysmergesubscriptions.subscription_type = @subscription_type_id
  12917.                 FOR READ ONLY       
  12918.  
  12919.             OPEN hC3
  12920.             FETCH hC3 INTO @subscriber_db
  12921.             WHILE (@@fetch_status <> -1)
  12922.                 BEGIN
  12923.                     EXECUTE dbo.sp_dropmergesubscription @publication = @publication,
  12924.                                                 @subscriber = @subscriber,
  12925.                                                 @subscriber_db = @subscriber_db,
  12926.                                                 @subscription_type = @subscription_type,
  12927.                                                 @ignore_distributor = @ignore_distributor,
  12928.                                                 @reserved = 1
  12929.  
  12930.                     FETCH hC3 INTO @subscriber_db
  12931.                 END
  12932.             CLOSE hC3
  12933.             DEALLOCATE hC3
  12934.             RETURN (0)
  12935.         END
  12936.  
  12937.     /*
  12938.     ** Validate that the publisher is a valid server
  12939.     */
  12940.     select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
  12941.     IF @publisher_srvid IS NULL
  12942.         BEGIN
  12943.             --RAISERROR (14010, 16, -1)
  12944.             RETURN (1)
  12945.         END
  12946.  
  12947.     select @pubid=pubid from sysmergepublications where name=@publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  12948.     if @pubid is NULL return (0)
  12949.     
  12950.     if exists (select * from sysmergesubscriptions where subid=@pubid 
  12951.         and pubid=@pubid and db_name<>db_name())
  12952.     RETURN (0)
  12953.     
  12954.     /*
  12955.     ** Get subscriptions from either local replicas or global replicas
  12956.     */
  12957.     select @subid = subs1.subid, @partnerid = subs2.subid, @subscriber_type = subs1.subscriber_type from
  12958.         sysmergesubscriptions   subs1,
  12959.         sysmergesubscriptions   subs2,
  12960.         sysmergepublications        pubs
  12961.         where subs1.srvid = @subscriber_srvid
  12962.             and subs1.db_name = @subscriber_db
  12963.             and subs2.srvid = @publisher_srvid
  12964.             and subs2.db_name = @publisher_db
  12965.             and subs1.pubid = subs2.subid
  12966.             and subs2.pubid = pubs.pubid
  12967.             and pubs.name = @publication
  12968.             and UPPER(pubs.publisher)=UPPER(@@servername)
  12969.             and pubs.publisher_db=db_name()
  12970.             and subs1.subscription_type = @subscription_type_id
  12971.             and (suser_sname(suser_sid()) = subs1.login_name OR is_member('db_owner')=1 OR is_srvrolemember('sysadmin') = 1)
  12972.  
  12973.     if @subid IS NULL
  12974.         begin
  12975.             -- raiserror (14050, 16, -1) 
  12976.             RETURN (0)
  12977.         end                 
  12978.  
  12979.     begin tran
  12980.     save TRAN dropmergesubscription
  12981.  
  12982.         /*
  12983.         ** Do not drop the subscription corresponding to the loopback subscription 
  12984.         */
  12985.         if (@subid <> @partnerid) 
  12986.             begin
  12987.                 /*
  12988.                 ** global/republisher subscriptions have to stay for a while even after being
  12989.                 ** dropped so that they won't regain lives for themselves. They would be cleanup eventually.
  12990.                 */
  12991.                 
  12992.                 if (@subscriber_type<>1) 
  12993.                     begin
  12994.                         delete from sysmergesubscriptions where subid = @subid
  12995.                         IF @@ERROR <> 0
  12996.                             GOTO FAILURE        
  12997.                         delete MSmerge_replinfo WHERE repid = @subid 
  12998.                         IF @@ERROR <> 0
  12999.                             GOTO FAILURE
  13000.                     end
  13001.                 else
  13002.                     begin
  13003.                         update sysmergesubscriptions set status=2 where subid=@subid
  13004.                         IF @@ERROR<>0
  13005.                             GOTO FAILURE
  13006.                     end 
  13007.  
  13008.                 /* 
  13009.                 ** The MobileSync registry entry needs to be dropped only for push subscriptions -  
  13010.                 ** i.e - need not be called when a pull subscription is created at the 
  13011.                 ** subscriber and sp_addmergesubscription is being called then.
  13012.                 */
  13013.                 IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push'
  13014.                 begin
  13015.                     /* Call sp_MSunregistersubscription so that the reg entries get deleted */
  13016.                     exec @retcode = dbo.sp_MSunregistersubscription @publisher = @@SERVERNAME,
  13017.                                     @publisher_db = @publisher_db,
  13018.                                     @publication = @publication,
  13019.                                     @subscriber = @subscriber,
  13020.                                     @subscriber_db = @subscriber_db
  13021.                     IF @retcode<>0 or @@ERROR<>0
  13022.                         GOTO FAILURE
  13023.  
  13024.                 END             
  13025.             end     
  13026.  
  13027.         /*
  13028.         ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
  13029.         */
  13030.         if @ignore_distributor = 0
  13031.         begin
  13032.             /*
  13033.             ** Get distribution server information for remote RPC call.
  13034.             */
  13035.             EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
  13036.                @distribdb   = @distribdb OUTPUT
  13037.             IF @@ERROR <> 0 or @retcode <> 0
  13038.                 BEGIN
  13039.                     GOTO FAILURE
  13040.                 END
  13041.  
  13042.             SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + 
  13043.                 '.dbo.sp_MSdrop_merge_subscription'
  13044.  
  13045.             EXEC @retcode = @distproc 
  13046.                 @@SERVERNAME, 
  13047.                 @publisher_db, 
  13048.                 @publication,
  13049.                 @subscriber, 
  13050.                 @subscriber_db,
  13051.                 @subscription_type
  13052.             IF @@ERROR <> 0 OR @retcode <> 0
  13053.                 begin   
  13054.                     goto FAILURE
  13055.                 end 
  13056.         end 
  13057.  
  13058.         /* 
  13059.         ** If last subscription is dropped and the DB is not enabled for publishing,
  13060.         ** then remove the merge system tables
  13061.         */
  13062.  
  13063.         IF (not exists (select * from sysmergesubscriptions )) 
  13064.             AND (select category & 4 FROM master..sysdatabases WHERE name = DB_NAME() collate database_default)=0
  13065.             BEGIN
  13066.                 execute @retcode = dbo.sp_MSdrop_mergesystables
  13067.                 if @@ERROR <> 0 or @retcode <> 0
  13068.                     begin
  13069.                         return (1)
  13070.                     end
  13071.             END         
  13072.  
  13073.     COMMIT TRAN
  13074.     /*
  13075.     ** Set back original settings
  13076.     */    
  13077.     IF @reserved = 0
  13078.     BEGIN
  13079.         IF @implicit_transaction <>0 
  13080.             SET IMPLICIT_TRANSACTIONS ON
  13081.         IF @close_cursor_at_commit <>0 
  13082.             SET CURSOR_CLOSE_ON_COMMIT ON
  13083.     END
  13084.     RETURN(0)       
  13085.  
  13086. FAILURE:
  13087.     /* UNDONE : This code is specific to 6.X nested transaction semantics */
  13088.     RAISERROR (14056, 16, -1)
  13089.     if @@TRANCOUNT > 0
  13090.     begin
  13091.         ROLLBACK TRANSACTION dropmergesubscription
  13092.         COMMIT TRANSACTION
  13093.     end
  13094.     /*
  13095.     ** Set back original settings
  13096.     */    
  13097.     IF @reserved = 0
  13098.     BEGIN
  13099.         IF @implicit_transaction <>0 
  13100.             SET IMPLICIT_TRANSACTIONS ON
  13101.         IF @close_cursor_at_commit <>0 
  13102.             SET CURSOR_CLOSE_ON_COMMIT ON
  13103.     END
  13104.     return (1)
  13105. go
  13106. exec dbo.sp_MS_marksystemobject sp_dropmergesubscription
  13107. go
  13108.  
  13109. grant execute on dbo.sp_dropmergesubscription to public
  13110. go
  13111.  
  13112. raiserror('Creating procedure sp_MShelpvalidationdate', 0,1)
  13113. GO
  13114.  
  13115. CREATE PROCEDURE sp_MShelpvalidationdate(
  13116. @publication        sysname,
  13117. @subscriber            sysname,
  13118. @subscriber_db        sysname
  13119. )AS
  13120. declare @pubid                    uniqueidentifier
  13121. declare @subscriber_srvid        int
  13122.  
  13123. -- Security check
  13124. if 1 <> is_member('db_owner')
  13125. begin    
  13126.     RAISERROR (15247, 11, -1)
  13127.     return (1)
  13128. end
  13129.  
  13130. select @pubid=pubid from sysmergepublications where name=@publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  13131. if @pubid is NULL return (0)
  13132.  
  13133. select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
  13134. select last_validated, attempted_validate from sysmergesubscriptions where pubid=@pubid and db_name=@subscriber_db and srvid=@subscriber_srvid
  13135.  
  13136. return (0)
  13137. GO
  13138. exec dbo.sp_MS_marksystemobject sp_MShelpvalidationdate
  13139. go
  13140.  
  13141.  
  13142. raiserror('Creating procedure sp_MSmergepublishdb', 0,1)
  13143. GO
  13144.  
  13145. CREATE PROCEDURE sp_MSmergepublishdb(
  13146.       @value     sysname,
  13147.       @ignore_distributor bit = 0
  13148.     ) AS
  13149.  
  13150.     SET NOCOUNT ON
  13151.  
  13152.     /*
  13153.     ** Declarations.
  13154.     */
  13155.     declare @command        nvarchar(255)
  13156.     declare @description    nvarchar(500)
  13157.     declare @cmptlevel      tinyint
  13158.     declare @db_name        sysname 
  13159.     declare @retcode        int
  13160.     declare @distributor    sysname
  13161.     declare @distribdb      sysname
  13162.     declare @category_name  sysname
  13163.     declare @agentname      sysname
  13164.     declare @working_directory nvarchar(255)
  13165.     /*
  13166.     ** Initialization
  13167.     */
  13168.  
  13169.     select @db_name = DB_NAME()
  13170.  
  13171.  
  13172.     /*
  13173.     ** Parameter check
  13174.     ** @value
  13175.     */
  13176.     IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true','false')
  13177.     BEGIN
  13178.       RAISERROR(14137,16,-1)
  13179.       RETURN(1)
  13180.     END
  13181.  
  13182.     /*
  13183.     ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
  13184.     */
  13185.     if @ignore_distributor = 0
  13186.     begin
  13187.         /*
  13188.         ** Test to see if the distributor is installed and online.
  13189.         */
  13190.         EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @directory=@working_directory OUTPUT,
  13191.            @distribdb   = @distribdb OUTPUT
  13192.  
  13193.         IF @@ERROR <> 0 or @retcode <> 0 or @distributor IS NULL or @distribdb IS NULL
  13194.         BEGIN
  13195.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  13196.                 RAISERROR (20028, 16, -1)
  13197.             ELSE
  13198.                 RAISERROR (20029, 16, -1)
  13199.             RETURN (1)
  13200.         END
  13201.     end
  13202.  
  13203.     /*
  13204.     ** Enable the database for publishing.
  13205.     */
  13206.     IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  13207.         BEGIN
  13208.             select @cmptlevel = cmptlevel from master..sysdatabases where name=db_name() collate database_default
  13209.             if @cmptlevel<70 OR @cmptlevel is NULL 
  13210.                 begin
  13211.                     RAISERROR(20061, 16, -1)
  13212.                     goto FAILURE
  13213.                 end
  13214.             execute @retcode = dbo.sp_MScreate_mergesystables
  13215.             if @@ERROR <> 0 or @retcode <> 0
  13216.                 begin
  13217.                     goto FAILURE
  13218.                 end
  13219.  
  13220.             END
  13221.  
  13222.     ELSE    /* Disable the database for publishing. */
  13223.         BEGIN 
  13224.            
  13225.           /*
  13226.           ** Remove all the registration entries for subscriptions
  13227.           */
  13228.             if not exists(select * from sysobjects where name = 'sysmergesubscriptions')
  13229.                 goto FAILURE
  13230.             exec @retcode = dbo.sp_dropmergesubscription @publication = 'all', 
  13231.                                             @subscriber = 'all', 
  13232.                                             @subscriber_db = 'all', 
  13233.                                             @subscription_type = 'both',
  13234.                                             @ignore_distributor = @ignore_distributor
  13235.             IF @@ERROR <> 0 or @retcode <> 0 
  13236.                 begin
  13237.                     goto FAILURE
  13238.                 end
  13239.             /*
  13240.             ** Remove all publications and articles in the database.
  13241.             */
  13242.             EXEC @retcode = dbo.sp_dropmergepublication @publication = 'all',
  13243.                 @ignore_distributor = @ignore_distributor
  13244.             IF @@ERROR <> 0 or @retcode <> 0 
  13245.                 begin
  13246.                     -- sp_dropmergepublication will raiserror 
  13247.                     goto FAILURE
  13248.                 end
  13249.                 
  13250.             If NOT EXISTS (select * from sysmergepublications)
  13251.                 BEGIN
  13252.                     execute @retcode = dbo.sp_MSdrop_mergesystables
  13253.                     if @@ERROR <> 0 or @retcode <> 0
  13254.                         begin
  13255.                             goto FAILURE
  13256.                         end
  13257.                 END
  13258.     
  13259.     END
  13260.         
  13261.         
  13262.         return 0
  13263. FAILURE:
  13264.     
  13265.     return (1)  
  13266.  
  13267. GO
  13268. exec dbo.sp_MS_marksystemobject sp_MSmergepublishdb
  13269. go
  13270.  
  13271. raiserror('Creating procedure sp_enumcustomresolvers', 0,1)
  13272. GO
  13273.  
  13274. CREATE PROCEDURE sp_enumcustomresolvers
  13275. --    @distributor parameter will be removed in the next version.   
  13276.     @distributor     sysname = NULL
  13277.     AS
  13278.     SET NOCOUNT ON
  13279.  
  13280.     declare @distributor_rpc sysname
  13281.     declare @return_status int
  13282.     declare @distproc nvarchar(150)
  13283.     declare @retcode int
  13284.  
  13285.     select @return_status = 0
  13286.  
  13287.    
  13288.     /*
  13289.     ** Get the distributor 
  13290.     ** Use local RPC if @distributor == @servername. This is used by UI
  13291.     ** before installing a distributor.
  13292.     */
  13293.     if @distributor = @@servername
  13294.         select @distributor_rpc = @@servername
  13295.     else
  13296.     begin
  13297.         EXEC @return_status = dbo.sp_helpdistributor @rpcsrvname = @distributor_rpc OUTPUT
  13298.         IF @@error <> 0 OR @return_status <> 0 OR @distributor_rpc IS NULL
  13299.         BEGIN
  13300.             RAISERROR (20036, 16, -1)
  13301.             RETURN (1)
  13302.         END
  13303.     end
  13304.  
  13305.     declare @key_exists int
  13306.     select @key_exists = 0
  13307.     create table #keyexists (keyexists int) 
  13308.     select @distproc = RTRIM(@distributor_rpc) + '.master..xp_regread'
  13309.     insert into #keyexists exec @distproc 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\ArticleResolver'
  13310.     select @key_exists = keyexists from #keyexists
  13311.     if (@key_exists = 1)
  13312.         begin
  13313.             select @distproc = RTRIM(@distributor_rpc) + '.master..xp_regenumvalues'
  13314.             exec @distproc 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\ArticleResolver'    
  13315.             if @@ERROR<>0 return (1)
  13316.         end
  13317.     drop table #keyexists
  13318.     RETURN (0)
  13319. GO
  13320. exec dbo.sp_MS_marksystemobject sp_enumcustomresolvers
  13321. go
  13322.  
  13323. grant execute on dbo.sp_enumcustomresolvers to public
  13324. go
  13325.  
  13326. raiserror('Creating procedure sp_changemergefilter', 0,1)
  13327. GO
  13328.  
  13329. create procedure sp_changemergefilter(
  13330.     @publication            sysname,
  13331.     @article                sysname,
  13332.     @filtername             sysname,
  13333.     @property               sysname,
  13334.     @value                  nvarchar(2000),
  13335.     @force_invalidate_snapshot bit = 0,    /* Force invalidate existing snapshot */
  13336.     @force_reinit_subscription bit = 0    /* Force reinit subscription */
  13337.     )AS
  13338.  
  13339.     set nocount on
  13340.  
  13341.     declare @pre_command        int
  13342.     declare @qual_object        nvarchar(132)
  13343.     declare @qual_join_object    nvarchar(132)
  13344.     declare @join_articlename    nvarchar(4000)
  13345.     declare @db_name        sysname
  13346.     declare @pubid          uniqueidentifier
  13347.     declare @artid          uniqueidentifier
  13348.     declare @object            sysname
  13349.     declare @join_object    sysname
  13350.     declare @retcode        int
  13351.     declare @join_filterid  int
  13352.     declare @join_objid     int
  13353.     declare @join_nickname  int
  13354.     declare @snapshot_ready int
  13355.  
  13356.     /*
  13357.     ** Security Check.
  13358.     ** Only the System Administrator (SA) or the Database Owner (dbo) can
  13359.     ** call this procedure
  13360.     */
  13361.     exec @retcode = dbo.sp_MSreplcheck_publish
  13362.     if @@ERROR <> 0 or @retcode <> 0
  13363.         return(1)
  13364.  
  13365.     /*
  13366.     ** Parameter Check: @join_articlename.
  13367.     ** The join_articlename cannot be NULL 
  13368.     */
  13369.     if @filtername is NULL
  13370.         begin
  13371.             raiserror (14043, 11, -1, '@filtername')
  13372.             return (1)
  13373.         end
  13374.  
  13375.     if @value is NULL or @value = ''
  13376.         begin
  13377.             raiserror (14043, 11, -1, '@value')
  13378.             return (1)
  13379.         end
  13380.  
  13381.     /*
  13382.     ** Parameter Check: @publication.
  13383.     ** The @publication id cannot be NULL and must conform to the rules
  13384.     ** for identifiers.
  13385.     */
  13386.     if @publication is NULL
  13387.         begin
  13388.             raiserror (14043, 11, -1, '@publication')
  13389.             return (1)
  13390.         end
  13391.     /*
  13392.     ** Get the pubid and make sure the publication exists
  13393.     */
  13394.     select @pubid = pubid, @snapshot_ready=snapshot_ready from sysmergepublications where 
  13395.         name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  13396.     if @pubid is NULL
  13397.         begin
  13398.             raiserror (20026, 16, -1, @publication)
  13399.             return (1)
  13400.         end
  13401.  
  13402.     select @db_name = db_name from sysmergesubscriptions
  13403.         where (pubid=@pubid) and (subid=@pubid)
  13404.         IF @db_name <> db_name()
  13405.         BEGIN
  13406.             RAISERROR (20047, 16, -1)
  13407.             RETURN (1)
  13408.         END
  13409.  
  13410.     /*
  13411.     ** Parameter Check: @article.
  13412.     ** Check to see that the @article is valid and does exist 
  13413.     */
  13414.     if @article is NULL
  13415.         begin
  13416.             raiserror (20045, 16, -1)
  13417.             return (1)
  13418.         end
  13419.         
  13420.     select @artid = artid, @object=object_name(objid), @pre_command=pre_creation_command from sysmergearticles where name = @article and pubid = @pubid  
  13421.     if @artid is NULL
  13422.         begin
  13423.             raiserror (20046, 16, -1)
  13424.             return (1)
  13425.         end
  13426.  
  13427.     
  13428.     select @join_filterid=join_filterid, @join_articlename=join_articlename from sysmergesubsetfilters
  13429.         where pubid=@pubid and artid=@artid and filtername=@filtername
  13430.  
  13431.     if @join_filterid is null
  13432.         begin
  13433.             raiserror (21362, 16, -1, @filtername) 
  13434.             return (1)
  13435.         end
  13436.  
  13437.      IF @property IS NULL
  13438.         BEGIN
  13439.             CREATE TABLE #temp (properties sysname collate database_default)
  13440.             INSERT INTO #temp VALUES ('filtername')
  13441.             INSERT INTO #temp VALUES ('join_filterclause')
  13442.             INSERT INTO #temp VALUES ('join_articlename')
  13443.             INSERT INTO #temp VALUES ('join_unique_key')
  13444.             select * FROM #tab1
  13445.             RETURN (0)
  13446.         END 
  13447.  
  13448.  
  13449.     if @value is null
  13450.         begin
  13451.             RAISERROR (14043, 16, -1, @property)
  13452.             return (1)
  13453.         end
  13454.  
  13455.     begin TRAN
  13456.     save TRAN change_filter
  13457.  
  13458.     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ('join_filterclause','join_articlename','join_unique_key')
  13459.         and @snapshot_ready>0
  13460.     begin
  13461.             -- 1 means'drop': which is the only option that support reintialization
  13462.             if @pre_command<>1                 
  13463.                 begin
  13464.                     raiserror(21419, 16, -1, @filtername, @article)
  13465.                     goto FAILURE            
  13466.                 end
  13467.             /*
  13468.             ** make sure we know we really want to do this.
  13469.             */
  13470.             if @force_invalidate_snapshot = 0
  13471.                 begin
  13472.                     raiserror(20607, 16, -1)
  13473.                     goto FAILURE
  13474.                 end
  13475.             if @force_reinit_subscription = 0
  13476.                 begin
  13477.                     raiserror(20608, 16, -1)
  13478.                     goto FAILURE
  13479.                 end
  13480.  
  13481.             update sysmergepublications set snapshot_ready=2 where pubid=@pubid
  13482.             if @@ERROR<>0
  13483.                 goto FAILURE
  13484.             exec @retcode = sp_MSreinitmergepublication @publication
  13485.             if @retcode<>0 or @@ERROR<>0
  13486.                 goto FAILURE
  13487.  
  13488.     end
  13489.     
  13490.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='join_filterclause'
  13491.         BEGIN
  13492.         /* check the validity of join_filterclause */
  13493.         select @join_object=object_name(objid) from sysmergearticles where name=@join_articlename and pubid=@pubid
  13494.         select @qual_object=QUOTENAME(@object)
  13495.         select @qual_join_object=QUOTENAME(@join_object)
  13496.         exec ('declare @test int select @test=1 from ' + @qual_object + ', ' + @qual_join_object + ' where ' + @value)
  13497.         if @@ERROR<>0
  13498.             begin
  13499.                 raiserror(21256, 16, -1, @value, @object)
  13500.                 goto FAILURE
  13501.             end
  13502.         update sysmergesubsetfilters set join_filterclause=@value
  13503.                 where join_filterid=@join_filterid
  13504.         execute @retcode = dbo.sp_MSsubsetpublication @publication
  13505.         if @@ERROR <> 0 or @retcode<>0
  13506.             goto FAILURE
  13507.         END
  13508.  
  13509.        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='join_unique_key'
  13510.         BEGIN
  13511.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true','false')
  13512.                 BEGIN
  13513.                       RAISERROR(14137,16,-1)
  13514.                       RETURN(1)
  13515.                  END
  13516.             if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  13517.                 update sysmergesubsetfilters set join_unique_key=1 where join_filterid=@join_filterid
  13518.             else
  13519.                 update sysmergesubsetfilters set join_unique_key=0 where join_filterid=@join_filterid
  13520.             if @@ERROR <> 0 or @retcode<>0
  13521.                 goto FAILURE
  13522.         END
  13523.  
  13524.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='filtername'
  13525.         BEGIN
  13526.             update sysmergesubsetfilters set filtername=@value
  13527.                 where join_filterid=@join_filterid
  13528.             if @@ERROR<>0
  13529.                 goto FAILURE
  13530.         END
  13531.  
  13532.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='join_articlename'
  13533.         BEGIN
  13534.             select @join_objid = objid from sysmergearticles where name = @value and pubid = @pubid
  13535.             
  13536.             IF @join_objid is NULL
  13537.             BEGIN
  13538.                 raiserror (14027, 11, -1, @value)
  13539.                 goto FAILURE
  13540.             END
  13541.  
  13542.             select @join_nickname = nickname from sysmergearticles where pubid = @pubid AND objid = @join_objid 
  13543.             if @join_nickname is NULL
  13544.             begin
  13545.                 raiserror (20001, 11, -1, @article, @publication)
  13546.                 goto FAILURE
  13547.             end
  13548.             
  13549.             update sysmergesubsetfilters set join_articlename=@value, join_nickname=@join_nickname
  13550.                 where join_filterid=@join_filterid
  13551.             if @@ERROR<>0
  13552.                 goto FAILURE
  13553.         END
  13554.         
  13555.     Commit TRAN
  13556.     return(0)
  13557.  
  13558. FAILURE:
  13559.     if @@TRANCOUNT > 0
  13560.     begin
  13561.         ROLLBACK TRANSACTION change_filter
  13562.         COMMIT TRANSACTION
  13563.     end
  13564.     RAISERROR (20038, 16, -1, @article, @publication)
  13565.     return(1)
  13566.  
  13567. go
  13568. exec dbo.sp_MS_marksystemobject sp_changemergefilter
  13569. go
  13570.  
  13571. grant execute on dbo.sp_changemergefilter to public
  13572. go
  13573.  
  13574. raiserror('Creating procedure sp_addmergefilter', 0,1)
  13575. GO
  13576.  
  13577. create procedure sp_addmergefilter(
  13578.     @publication            sysname,            /* publication name */
  13579.     @article                sysname,            /* article name */
  13580.     @filtername             sysname,            /* join filter name */
  13581.     @join_articlename       sysname,            /* Name of the table being joined to the base table */
  13582.     @join_filterclause      nvarchar(2000),     /* filter clause qualifying the join */             
  13583.     @join_unique_key        int = 0,
  13584.     @force_invalidate_snapshot bit = 0,            /* Force invalidate existing snapshot */
  13585.     @force_reinit_subscription bit = 0            /* Force reinit subscription */
  13586.     )AS
  13587.  
  13588.     set nocount on
  13589.  
  13590.     /*
  13591.     ** Declarations.
  13592.     */
  13593.     declare @snapshot_ready        int
  13594.     declare @db_name            sysname
  13595.     declare @pubid              uniqueidentifier                
  13596.     declare @artid              uniqueidentifier
  13597.     declare @art_nickname       int
  13598.     declare @join_nickname      int
  13599.     declare @db                 sysname
  13600.     declare @qual_object        nvarchar(150)
  13601.     declare @qual_join_object    nvarchar(150)
  13602.     declare @qual_object_view    nvarchar(150)
  13603.     declare @qual_join_object_view nvarchar(150)
  13604.     
  13605.     declare @object             sysname
  13606.     declare @vertical            int
  13607.     declare @join_vertical        int
  13608.     declare @join_object        nvarchar(140)
  13609.     declare @object_view        nvarchar(140)
  13610.     declare @join_object_view    nvarchar(140)
  13611.     declare @owner              sysname
  13612.     declare @retcode            int
  13613.     declare @join_objid         int
  13614.     declare @objid                int
  13615.     declare @status             int
  13616.     declare @column_list        nvarchar(4000)
  13617.     
  13618.     /* make sure current database is enabled for merge replication */
  13619.     exec @retcode=dbo.sp_MSCheckmergereplication
  13620.     if @@ERROR<>0 or @retcode<>0
  13621.         return (1)
  13622.  
  13623.     /*
  13624.     ** Security Check.
  13625.     ** Only the System Administrator (SA) or the Database Owner (dbo) can
  13626.     ** add an article to a publication.
  13627.     */
  13628.     exec @retcode = dbo.sp_MSreplcheck_publish
  13629.     if @@ERROR <> 0 or @retcode <> 0
  13630.         return(1)
  13631.  
  13632.     /*
  13633.     ** Parameter Check: @filtername.
  13634.     ** The join_filter_name cannot be NULL 
  13635.     */
  13636.     if @filtername is NULL
  13637.         begin
  13638.             raiserror (14043, 11, -1, @filtername)
  13639.             return (1)
  13640.         end
  13641.  
  13642.     if @join_filterclause is NULL or @join_filterclause = ''
  13643.         begin
  13644.             raiserror (14043, 11, -1, '@join_filterclause')
  13645.             return (1)
  13646.         end
  13647.  
  13648.     /*
  13649.     ** Parameter Check: @publication.
  13650.     ** The @publication id cannot be NULL and must conform to the rules
  13651.     ** for identifiers.
  13652.     */
  13653.     if @publication is NULL
  13654.         begin
  13655.             raiserror (14003, 16, -1)
  13656.             return (1)
  13657.         end
  13658.  
  13659.     
  13660.     /*
  13661.     ** Get the pubid and make sure the publication exists
  13662.     */
  13663.     select @pubid = pubid, @snapshot_ready=snapshot_ready from sysmergepublications 
  13664.         where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  13665.     if @pubid is NULL
  13666.         begin
  13667.             raiserror (20026, 16, -1, @publication)
  13668.             return (1)
  13669.         end
  13670.  
  13671.     if @snapshot_ready>0
  13672.         begin
  13673.             /*
  13674.             ** make sure we know we really want to do this.
  13675.             */
  13676.             if @force_invalidate_snapshot = 0
  13677.                 begin
  13678.                     raiserror(21366, 16, -1, @filtername)
  13679.                     goto FAILURE
  13680.                 end
  13681.             if @force_reinit_subscription = 0
  13682.                 begin
  13683.                     raiserror(21367, 16, -1, @filtername)
  13684.                     goto FAILURE
  13685.                 end
  13686.  
  13687.             update sysmergepublications set snapshot_ready=2 where pubid=@pubid
  13688.             if @@ERROR<>0
  13689.                 goto FAILURE
  13690.             exec @retcode = sp_MSreinitmergepublication @publication
  13691.             if @retcode<>0 or @@ERROR<>0
  13692.                 goto FAILURE
  13693.  
  13694.         end
  13695.  
  13696.     select @db_name = db_name from sysmergesubscriptions
  13697.         where (pubid=@pubid) and (subid=@pubid) 
  13698.         IF @db_name <> db_name()
  13699.         BEGIN
  13700.             RAISERROR (20047, 16, -1)
  13701.             RETURN (1)
  13702.         END        
  13703.     /*
  13704.     ** Parameter Check: @article.
  13705.     ** Check to see that the @article is valid and does exist 
  13706.     */
  13707.     if @article is NULL
  13708.         begin
  13709.             raiserror (20045, 16, -1)
  13710.             return (1)
  13711.         end
  13712.         
  13713.     select @artid = artid, @objid=objid, @vertical=vertical_partition, @art_nickname = nickname from sysmergearticles where name = @article and pubid = @pubid  
  13714.     if @artid is NULL
  13715.         begin
  13716.             raiserror (20046, 16, -1)
  13717.             return (1)
  13718.         end
  13719.         
  13720.     /*
  13721.     **  Get the id of the @join_articlename
  13722.     */
  13723.     select @join_objid = objid, @join_vertical= vertical_partition from sysmergearticles where name=@join_articlename and pubid = @pubid
  13724.     
  13725.     IF @join_objid is NULL
  13726.         BEGIN
  13727.             raiserror (14027, 11, -1, @join_articlename)
  13728.             return (1)
  13729.         END
  13730.         
  13731.     /* check the validity of join_filterclause */
  13732.     select @object = object_name(@objid)
  13733.  
  13734.     select @join_object = object_name(@join_objid)
  13735.     
  13736.     select @object_view = @object
  13737.     select @join_object_view = @join_object
  13738.             
  13739.     /* is current article vertically partitioned */
  13740.     if @vertical=1
  13741.     begin
  13742.           select @object_view = 'OBJECT_VIEW_' + @object
  13743.  
  13744.           select @qual_object_view=QUOTENAME(@object_view)
  13745.           select @qual_object=QUOTENAME(@object)
  13746.           
  13747.           exec @retcode = sp_MSgetcolumnlist @pubid, @column_list OUTPUT, @objid
  13748.           exec ('create view ' + @qual_object_view + ' as select ' + @column_list + ' from ' + @qual_object)
  13749.           if @@ERROR<>0
  13750.               goto FAILURE
  13751.           
  13752.     end
  13753.  
  13754.     /* is join article vertically partitioned */
  13755.     if @join_vertical=1
  13756.     begin
  13757.           select @join_object_view = 'JOIN_OBJECT_VIEW_' + @join_object
  13758.           select @qual_join_object_view = QUOTENAME(@join_object_view)
  13759.           select @qual_join_object=QUOTENAME(@join_object)
  13760.           
  13761.           exec @retcode = sp_MSgetcolumnlist @pubid, @column_list OUTPUT, @join_objid
  13762.           exec ('create view ' + @qual_join_object_view + ' as select ' + @column_list + ' from ' + @qual_join_object)
  13763.           if @@ERROR<>0
  13764.           begin
  13765.               exec('drop view ' + @qual_object_view)
  13766.               goto FAILURE
  13767.           end
  13768.          
  13769.     end
  13770.  
  13771.     select @qual_object_view=QUOTENAME(@object_view)
  13772.     select @qual_join_object_view = QUOTENAME(@join_object_view)
  13773.     select @qual_join_object=QUOTENAME(@join_object)
  13774.     select @qual_object=QUOTENAME(@object)
  13775.  
  13776.     exec ('declare @test int select @test=1 from ' + @qual_object_view + ' ' + @qual_object + ', ' + @qual_join_object_view + ' ' + @qual_join_object + ' where ' + @join_filterclause)
  13777.     if @@ERROR<>0
  13778.         begin
  13779.             if @vertical=1
  13780.                 exec ('drop view ' + @qual_object_view)
  13781.             if @join_vertical=1
  13782.                  exec ('drop view ' + @qual_join_object_view)
  13783.             raiserror(21256, 16, -1, @join_filterclause, @article)
  13784.             return (1)
  13785.         end
  13786.         
  13787.     if @vertical=1
  13788.         exec ('drop view ' + @qual_object_view)
  13789.     if @join_vertical=1
  13790.          exec ('drop view ' + @qual_join_object_view)
  13791.     
  13792.     select @join_nickname = nickname from sysmergearticles where pubid = @pubid AND objid = @join_objid 
  13793.     if @join_nickname is NULL
  13794.         begin
  13795.             raiserror (20001, 11, -1, @article, @publication)
  13796.             return (1)
  13797.         end
  13798.  
  13799.     IF NOT EXISTS (select * from sysmergearticles where pubid=@pubid AND nickname = @join_nickname)
  13800.         BEGIN
  13801.             RAISERROR (20046, 16, -1) /* Only the original publisher can do so */
  13802.             RETURN (1)
  13803.         END
  13804.     
  13805.     /*
  13806.     ** Make sure that the table name specified is a table and not a view.
  13807.     */
  13808.     
  13809.     if NOT exists (select * from sysobjects
  13810.         where id = @join_objid AND type = 'U')
  13811.         begin
  13812.             raiserror (14028, 16, -1)
  13813.             return (1)
  13814.         end
  13815.  
  13816.     /*
  13817.     **  Add the join filter to sysmergesubsetfilters if it is not already there
  13818.     */
  13819.  
  13820.     IF exists (select * from sysmergesubsetfilters 
  13821.     where filtername=@filtername and  pubid=@pubid and artid=@artid) 
  13822.         begin
  13823.             raiserror (20002, 16, -1, @filtername, @article, @publication)
  13824.             return (1)
  13825.         end
  13826.     
  13827.     insert INTO sysmergesubsetfilters(filtername, pubid, artid, art_nickname, join_articlename, join_nickname, join_unique_key, join_filterclause)
  13828.         values(@filtername, @pubid, @artid, @art_nickname, @join_articlename, @join_nickname, @join_unique_key, @join_filterclause)                 
  13829.     if @@error <> 0
  13830.         begin
  13831.             goto FAILURE
  13832.         end
  13833.     execute @retcode = dbo.sp_MSsubsetpublication @publication
  13834.     if @@ERROR <> 0 or @retcode <>0
  13835.         goto FAILURE
  13836.     
  13837.     return (0)
  13838.     
  13839. FAILURE:
  13840.     RAISERROR (20038, 16, -1, @article, @publication)
  13841.     return (1)
  13842.  
  13843. go
  13844. exec dbo.sp_MS_marksystemobject sp_addmergefilter
  13845. go
  13846.  
  13847. grant execute on dbo.sp_addmergefilter to public
  13848. go
  13849.  
  13850. raiserror('Creating procedure sp_dropmergefilter', 0,1)
  13851. GO
  13852.  
  13853. create procedure sp_dropmergefilter
  13854.     @publication            sysname,            /* publication name */
  13855.     @article                sysname,            /* article name */
  13856.     @filtername             sysname,             /* Name of the table being joined to the base table */
  13857.     @force_invalidate_snapshot bit = 0
  13858.     AS
  13859.  
  13860.     set nocount on
  13861.  
  13862.     /*
  13863.     ** Declarations.
  13864.     */
  13865.     declare @pubid                  uniqueidentifier                
  13866.     declare @artid                  uniqueidentifier
  13867.     declare @join_objid             int
  13868.     declare @retcode                int
  13869.     declare @join_filterid          int
  13870.     declare @db_name                sysname
  13871.     declare @allow_anonymous        int
  13872.     declare @snapshot_ready            tinyint
  13873.  
  13874.     /* make sure current database is enabled for merge replication */
  13875.     exec @retcode=dbo.sp_MSCheckmergereplication
  13876.     if @@ERROR<>0 or @retcode<>0
  13877.         return (1)
  13878.  
  13879.     /* 
  13880.     ** Security Check.
  13881.     */
  13882.     exec @retcode=sp_MSreplcheck_publish
  13883.     if @@ERROR <> 0 or @retcode <> 0
  13884.         return (1)
  13885.  
  13886.     /*
  13887.     ** Parameter Check: @publication.
  13888.     ** The @publication id cannot be NULL and must conform to the rules
  13889.     ** for identifiers.
  13890.     */
  13891.     
  13892.     if @publication is NULL
  13893.         begin
  13894.             raiserror (14003, 16, -1)
  13895.             return (1)
  13896.         end
  13897.  
  13898.     /*
  13899.     ** Get the pubid, and check if this publication exists.
  13900.     */
  13901.     select @pubid = pubid, @snapshot_ready=snapshot_ready, @allow_anonymous=allow_anonymous from sysmergepublications 
  13902.         where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  13903.     if @pubid is NULL
  13904.         begin
  13905.             raiserror (20026, 16, -1, @publication )
  13906.             return (1)
  13907.         end
  13908.  
  13909.     select @db_name = db_name from sysmergesubscriptions
  13910.         where (pubid=@pubid) and (subid=@pubid) 
  13911.         IF @db_name <> db_name()
  13912.         BEGIN
  13913.             RAISERROR (20047, 16, -1)
  13914.             RETURN (1)
  13915.         END
  13916.     
  13917.     /*
  13918.     ** Parameter Check: @article.
  13919.     ** Check to see that the @article is valid, and if it exists
  13920.     */
  13921.     if @article is NULL
  13922.         begin
  13923.             raiserror (20045, 16, -1)
  13924.             return (1)
  13925.         end
  13926.  
  13927.     if @snapshot_ready>0 and (@allow_anonymous=1 or 
  13928.         exists (select * from sysmergesubscriptions where pubid=@pubid and subid<>pubid and status=1))
  13929.         BEGIN
  13930.             RAISERROR (21372, 16, -1, @filtername, @publication)
  13931.             RETURN (1)
  13932.         END
  13933.  
  13934.      if @snapshot_ready>0
  13935.         begin
  13936.             if @force_invalidate_snapshot = 0
  13937.                 begin
  13938.                     raiserror(21382, 16, -1, @filtername)
  13939.                     return (1)
  13940.                 end
  13941.             update sysmergepublications set snapshot_ready=2 where pubid=@pubid
  13942.             if @@ERROR<>0
  13943.                 return (1)
  13944.         end
  13945.    
  13946.        
  13947.     select @artid = artid from sysmergearticles where name = @article and pubid = @pubid  
  13948.     if @artid is NULL
  13949.         begin
  13950.             raiserror (20046, 16, -1)
  13951.             return (1)
  13952.         end
  13953.     
  13954.  
  13955.     select @join_filterid = join_filterid from sysmergesubsetfilters
  13956.         where pubid = @pubid AND artid= @artid AND filtername=@filtername  
  13957.     
  13958.     /*
  13959.     **  Remove the join filter from sysmergesubsetfilters
  13960.     */
  13961.     delete from sysmergesubsetfilters
  13962.         where join_filterid = @join_filterid
  13963.     if @@error <> 0
  13964.         begin
  13965.             goto FAILURE
  13966.         end
  13967.  
  13968.     /*
  13969.     ** set the pub type to subset or full as appropriate
  13970.     */
  13971.     exec @retcode=sp_MSsubsetpublication @publication
  13972.     if @@ERROR <> 0 or @retcode<>0
  13973.         begin
  13974.             goto FAILURE
  13975.         end
  13976.  
  13977.     return(0)
  13978. FAILURE:
  13979.     RAISERROR (20039, 16, -1, @article, @publication)
  13980.     return (1)
  13981. go
  13982.  
  13983. exec dbo.sp_MS_marksystemobject sp_dropmergefilter
  13984. go
  13985. grant execute on dbo.sp_dropmergefilter to public
  13986. go
  13987.  
  13988. raiserror('Creating procedure sp_helpmergefilter', 0,1)
  13989. GO
  13990.  
  13991. create procedure sp_helpmergefilter
  13992.     @publication            sysname,        /* publication name */
  13993.     @article                sysname = '%',          /* article name */ 
  13994.     @filtername             sysname = '%'
  13995.     AS
  13996.  
  13997.     set nocount on
  13998.  
  13999.     /*
  14000.     ** Declarations.
  14001.     */
  14002.     declare @pubid                  uniqueidentifier                
  14003.     declare @artid                  uniqueidentifier
  14004.     declare @retcode                int
  14005.  
  14006.     /* 
  14007.     ** No security checking is needed for sp_help??
  14008.     */
  14009.  
  14010.  
  14011.     /*
  14012.     **  Calling sp_help* is all right whether current database is enabled for pub/sub or not
  14013.     */
  14014.     IF not exists (select * from sysobjects where name='sysmergesubscriptions')
  14015.         RETURN (0)
  14016.         
  14017.     /*
  14018.     ** Parameter Check: @publication.
  14019.     ** The @publication id cannot be NULL and must conform to the rules
  14020.     ** for identifiers.
  14021.     */
  14022.     if @publication is NULL
  14023.         begin
  14024.             raiserror (14003, 16, -1)
  14025.             return (1)
  14026.         end
  14027.     /*
  14028.     ** Get the pubid and check if the publication does exist
  14029.     */
  14030.     select @pubid = pubid from sysmergepublications 
  14031.         where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  14032.     if @pubid is NULL
  14033.         begin
  14034.             raiserror (20026, 16, -1, @publication)
  14035.             return (1)
  14036.         end
  14037.  
  14038.     /*
  14039.     ** Parameter Check: @article.
  14040.     ** If an @article is specified, make sure it exists
  14041.     */
  14042.     select @artid = artid from sysmergeextendedarticlesview where name = @article and pubid = @pubid  
  14043.     if @artid is NULL and (@article <> '%' or @filtername <> '%')
  14044.         begin
  14045.             raiserror (20046, 16, -1)
  14046.             return (1)
  14047.         end
  14048.  
  14049.     /*
  14050.     **  Return the join filters from sysmergesubsetfilters
  14051.     */
  14052.  
  14053. IF @filtername <> '%'
  14054.     select distinct join_filterid, filtername, 'join article name' = j_a.name, join_filterclause, f.join_unique_key,
  14055.             'base table owner' = b_u.name, 'base table name' = b_o.name, 'join table owner' = j_u.name, 'join table name' = j_o.name,
  14056.             'article name' = b_a.name
  14057.         from sysmergesubsetfilters f, sysobjects j_o, sysobjects b_o, sysusers j_u,
  14058.             sysusers b_u, sysmergeextendedarticlesview j_a, sysmergeextendedarticlesview b_a
  14059.         where   f.pubid = @pubid AND b_a.pubid = @pubid
  14060.             AND f.filtername = @filtername
  14061.             AND f.artid = @artid 
  14062.             AND f.artid = b_a.artid AND b_o.id = b_a.objid
  14063.             AND b_u.uid = b_o.uid
  14064.             AND f.join_nickname = j_a.nickname AND j_o.id = j_a.objid and j_a.pubid = @pubid
  14065.             AND j_u.uid = j_o.uid
  14066.            ORDER BY j_o.name, b_o.name
  14067.  ELSE
  14068.     begin
  14069.     if @artid is not null
  14070.     select distinct join_filterid, filtername, 'join article name' = j_a.name, join_filterclause, f.join_unique_key,
  14071.             'base table owner' = b_u.name, 'base table name' = b_o.name, 'join table owner' = j_u.name, 'join table name' = j_o.name,
  14072.             'article name' = b_a.name
  14073.         from sysmergesubsetfilters f, sysobjects j_o, sysobjects b_o, sysusers j_u,
  14074.             sysusers b_u, sysmergeextendedarticlesview j_a, sysmergeextendedarticlesview b_a
  14075.         where   f.pubid = @pubid AND b_a.pubid = @pubid
  14076.             AND f.artid = @artid 
  14077.             AND f.artid = b_a.artid AND b_o.id = b_a.objid
  14078.             AND b_u.uid = b_o.uid
  14079.             AND f.join_nickname = j_a.nickname AND j_o.id = j_a.objid and j_a.pubid = @pubid
  14080.             AND j_u.uid = j_o.uid
  14081.            ORDER BY j_o.name, b_o.name
  14082.     else
  14083.     select distinct join_filterid, filtername, 'join article name' = j_a.name, join_filterclause, f.join_unique_key,
  14084.             'base table owner' = b_u.name, 'base table name' = b_o.name, 'join table owner' = j_u.name, 'join table name' = j_o.name,
  14085.             'article name' = b_a.name
  14086.         from sysmergesubsetfilters f, sysobjects j_o, sysobjects b_o, sysusers j_u,
  14087.             sysusers b_u, sysmergeextendedarticlesview j_a, sysmergeextendedarticlesview b_a
  14088.         where   f.pubid = @pubid AND b_a.pubid = @pubid
  14089.             AND f.artid = b_a.artid AND b_o.id = b_a.objid
  14090.             AND b_u.uid = b_o.uid
  14091.             AND f.join_nickname = j_a.nickname AND j_o.id = j_a.objid and j_a.pubid = @pubid
  14092.             AND j_u.uid = j_o.uid
  14093.            ORDER BY j_o.name, b_o.name
  14094.     end
  14095.     return(0)
  14096. go
  14097. exec dbo.sp_MS_marksystemobject sp_helpmergefilter
  14098. go
  14099.  
  14100. grant execute on dbo.sp_helpmergefilter to public
  14101. go
  14102.  
  14103. raiserror('Creating procedure sp_MSscript_dri', 0,1)
  14104. go
  14105. create procedure sp_MSscript_dri
  14106.     (@publication   sysname, 
  14107.     @article        sysname)
  14108. AS
  14109.  
  14110. declare @pubid  uniqueidentifier
  14111.     
  14112. select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  14113.         
  14114. -- Security check
  14115. if (1 <> {fn ISPALUSER(@pubid)})
  14116. begin    
  14117.     RAISERROR (15247, 11, -1)
  14118.     return (1)
  14119. end
  14120.  
  14121. select rkeyid, fkeyid from sysreferences 
  14122.         where fkeyid in (select objid from sysmergearticles where pubid = @pubid and name = @article) 
  14123.             and rkeyid not in (select objid from sysmergearticles   where pubid = @pubid)
  14124. go
  14125. exec dbo.sp_MS_marksystemobject sp_MSscript_dri
  14126. go
  14127. grant execute on dbo.sp_MSscript_dri to public
  14128. go
  14129.  
  14130.  
  14131. raiserror('Creating procedure sp_MSenumpubreferences', 0,1)
  14132. GO
  14133. create procedure sp_MSenumpubreferences (@publication sysname)
  14134. as
  14135.     declare @pubid uniqueidentifier
  14136.     declare @retcode int
  14137.     
  14138.     /* 
  14139.     ** Security Check.
  14140.     */
  14141.     exec @retcode = dbo.sp_MSreplcheck_publish
  14142.     if @@ERROR <> 0 or @retcode <> 0
  14143.         return(1)
  14144.  
  14145.     /* make sure current database is enabled for merge replication */
  14146.     exec @retcode=dbo.sp_MSCheckmergereplication
  14147.     if @@ERROR<>0 or @retcode<>0
  14148.         return (1)
  14149.  
  14150.     select @pubid = pubid from sysmergepublications where
  14151.         name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  14152.     if @pubid is null
  14153.         BEGIN
  14154.             RAISERROR (20026, 16, -1, @publication)
  14155.             RETURN (1)
  14156.         END
  14157.     select distinct ReferencingObject = object_name(rkeyid), ArticleObject  = object_name(fkeyid) 
  14158.         from sysreferences r, sysmergearticles
  14159.         where r.fkeyid in (select objid from sysmergearticles where pubid = @pubid) 
  14160.             and r.rkeyid not in (select objid from sysmergearticles where pubid = @pubid)
  14161.  
  14162.     select distinct ReferencedObject = object_name(fkeyid), ArticleObject = object_name(rkeyid) from sysreferences r
  14163.         where r.rkeyid in (select objid from sysmergearticles
  14164.             where pubid = @pubid) and
  14165.         r.fkeyid not in (select objid from sysmergearticles
  14166.             where pubid = @pubid)       
  14167.  
  14168.     -- patch. We need to check if the publication role is already added.
  14169.     -- this has to be done here before the snapshot agent calls sp_Mspublicationview
  14170.     declare @role sysname
  14171.     exec @retcode = sp_MSrepl_FixPALRole @pubid, @role output
  14172.     if (@role is NULL or @retcode <> 0 or @@error <> 0)
  14173.     begin
  14174.         -- add appropriate error message here
  14175.         return 1
  14176.     end
  14177.  
  14178.     -- we also need to fix the pal role for other publications which share an article
  14179.     -- with the current publication and the role for those publications are not
  14180.     -- present yet
  14181.     declare @pubidother uniqueidentifier
  14182.     declare pubs_cursor cursor LOCAL FAST_FORWARD
  14183.     for (select a.pubid from dbo.sysmergearticles a, dbo.sysmergepublications p
  14184.             where a.pubid <> @pubid and a.pubid = p.pubid 
  14185.                 and LOWER(p.publisher) collate database_default = LOWER(@@servername) collate database_default and p.publisher_db = DB_NAME() and artid in 
  14186.                  (select artid from dbo.sysmergearticles where pubid = @pubid)) 
  14187.     open pubs_cursor
  14188.     fetch pubs_cursor into @pubidother
  14189.     while (@@fetch_status <> -1)
  14190.     begin
  14191.         exec @retcode = sp_MSrepl_FixPALRole @pubidother, @role output
  14192.         if (@role is NULL or @retcode <> 0 or @@error <> 0)
  14193.         begin
  14194.             return 1
  14195.         end
  14196.         fetch pubs_cursor into @pubidother
  14197.     end
  14198.     close pubs_cursor
  14199.     deallocate pubs_cursor
  14200.     
  14201.     return (0)
  14202. go
  14203.  
  14204. exec dbo.sp_MS_marksystemobject sp_MSenumpubreferences
  14205. go
  14206.  
  14207. grant execute on dbo.sp_MSenumpubreferences to public
  14208. go
  14209.  
  14210. raiserror('Creating procedure sp_MSsubsetpublication', 0,1)
  14211. GO
  14212.  
  14213. create procedure sp_MSsubsetpublication (@publication sysname)
  14214. as
  14215.     declare @pubid          uniqueidentifier
  14216.     declare @false          bit
  14217.     declare @true           bit
  14218.     declare @boolean_filter bit
  14219.     declare @join_filter    bit
  14220.     declare @full           int
  14221.     declare @subset         int
  14222.     declare @unsynced       int
  14223.  
  14224.     /*
  14225.     ** Initializations
  14226.     */
  14227.     select @true        = 1
  14228.     select @false       = 0
  14229.     select @full        = 0     /* Const: publication type 'full' */
  14230.     select @subset      = 1     /* Const: publication type 'subset' */
  14231.     select @unsynced    = 1
  14232.     
  14233.     if not exists (select * from sysobjects where name = 'sysmergepublications')
  14234.         BEGIN
  14235.             RAISERROR (20054, 16, -1)
  14236.             RETURN (1)
  14237.         END 
  14238.  
  14239.     select @pubid = pubid from sysmergepublications where
  14240.         name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  14241.     if @pubid is null
  14242.         BEGIN
  14243.             RAISERROR (20026, 16, -1, @publication)
  14244.             RETURN (1)
  14245.         END
  14246.  
  14247.     /* 
  14248.     ** Set the publication_type to subset if the publication has either a boolean or a join filter
  14249.     */
  14250.     if exists (select * from sysmergearticles where pubid = @pubid and len(subset_filterclause) > 0)
  14251.         set @boolean_filter = @true
  14252.     if exists (select * from sysmergesubsetfilters where pubid = @pubid)
  14253.         set @join_filter = @true
  14254.  
  14255.     /*
  14256.     ** For subset publications set the article status to be unsynced so that the triggers can be regenerated.
  14257.     */
  14258.     if (@boolean_filter = 1 OR @join_filter = 1)        
  14259.         begin
  14260.             update sysmergepublications set publication_type = @subset where pubid = @pubid
  14261.             if @@ERROR <> 0 return (1)
  14262.             update sysmergearticles set status = @unsynced where pubid = @pubid
  14263.             if @@ERROR <> 0 return (1)
  14264.         end         
  14265.     else
  14266.         update sysmergepublications set publication_type = @full where pubid = @pubid               
  14267.     if @@ERROR <> 0 return (1)
  14268.         
  14269.     return(0)           
  14270. go
  14271.  
  14272. exec dbo.sp_MS_marksystemobject sp_MSsubsetpublication
  14273. go
  14274. raiserror('Creating procedure sp_MSindexcolfrombin', 0,1)
  14275. GO
  14276.  
  14277. create procedure sp_MSindexcolfrombin
  14278.     @object_id      int,
  14279.     @col_index      int,
  14280.     @colids_bin     varbinary(256),
  14281.     @colname        sysname output,
  14282.     @columns        varbinary(128) = NULL
  14283.     AS
  14284.     /* Declare variables */
  14285.     declare @start_byte int
  14286.     declare @colid int
  14287.     declare @retcode int
  14288.     set @colid = unicode( substring( convert( nvarchar(128),@colids_bin ), @col_index, 1 ) )
  14289.     select @colname = QUOTENAME(name) from syscolumns where id = @object_id and colid = @colid
  14290.  
  14291.     /* vertical partitioning is ON */
  14292.     if @columns is not NULL
  14293.     begin
  14294.         /* see if this column is currently in the vertical partitioning */
  14295.         exec @retcode = sp_MStestbit @bm=@columns, @coltotest=@colid
  14296.         if @retcode=0
  14297.             select @colname = NULL
  14298.     end
  14299.     return (0)
  14300. GO
  14301. exec dbo.sp_MS_marksystemobject sp_MSindexcolfrombin
  14302. go
  14303.  
  14304. raiserror('Creating procedure sp_MSmakejoinfilter', 0,1)
  14305. GO
  14306.  
  14307. create procedure sp_MSmakejoinfilter
  14308.     @publication    sysname,
  14309.     @article        sysname,
  14310.     @base_objid     int,
  14311.     @join_objid     int,
  14312.     @join_unique    int
  14313.     AS
  14314.  
  14315.     /* Declare additional variables */
  14316.     declare     @table_name nvarchar(140)
  14317.     declare     @join_table nvarchar(140)
  14318.     declare     @join_article sysname
  14319.     declare     @filt_name  sysname
  14320.     declare     @basecol    sysname
  14321.     declare     @joincol    sysname
  14322.     declare     @keycnt     int
  14323.     declare     @basekeys   varbinary(32)
  14324.     declare     @joinkeys   varbinary(32)
  14325.     declare     @base_columns    varbinary(128)
  14326.     declare     @join_columns    varbinary(128)
  14327.     declare     @keyindex   int
  14328.     declare     @filtclause nvarchar(3000)
  14329.     declare     @filtpiece  nvarchar(500)
  14330.     declare     @qual_jointable nvarchar(270)
  14331.     declare     @retcode    smallint
  14332.     declare     @pubid      uniqueidentifier
  14333.     declare     @first_piece bit
  14334.  
  14335.     select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name()
  14336.  
  14337.     select @base_columns=0x00 -- so that no base column name will be returned if following query does not find a match
  14338.     select @join_columns=0x00 -- same as above
  14339.     
  14340.     select @base_columns=columns from sysmergearticles where pubid=@pubid and objid=@base_objid
  14341.     select @join_columns=columns from sysmergearticles where pubid=@pubid and objid=@join_objid
  14342.     
  14343.     /* Are we adding join filter on referencing table (@join_unique = 1) or on unique key table ? */
  14344.     if @join_unique = 1
  14345.     /* Select the keycnt, fkeys, rkeys, and filter name from sysreferences */
  14346.         select @keycnt = keycnt, @basekeys = forkeys, @joinkeys = refkeys, @filt_name = object_name(constid)
  14347.             from sysreferences where fkeyid = @base_objid and rkeyid = @join_objid
  14348.     else
  14349.         select @keycnt = keycnt, @basekeys = refkeys, @joinkeys = forkeys, @filt_name = object_name(constid)
  14350.             from sysreferences where rkeyid = @base_objid and fkeyid = @join_objid
  14351.     
  14352.     /* Set up object names - we use them as correlation values */
  14353.     set @table_name = QUOTENAME(object_name(@base_objid))
  14354.     set @join_table = QUOTENAME(object_name(@join_objid))
  14355.     select @join_article = name from sysmergearticles where objid = @join_objid and pubid=@pubid
  14356.  
  14357.     -- set @qual_jointable = @join_owner + '.' + @join_table
  14358.  
  14359.     /* Loop over keys, building up our join filter clause */
  14360.     set @keyindex = 1
  14361.     set @first_piece = 0
  14362.     while @keyindex <= @keycnt
  14363.         begin
  14364.         /* Get the column names */
  14365.         
  14366.         /* also pass in vertical partitioning binary to excluded columns that are not in the current partition */
  14367.         exec dbo.sp_MSindexcolfrombin @base_objid, @keyindex, @basekeys, @basecol output, @base_columns
  14368.         if @@ERROR<>0 return (1)
  14369.         exec dbo.sp_MSindexcolfrombin @join_objid, @keyindex, @joinkeys, @joincol output, @join_columns
  14370.         if @@ERROR<>0 return (1)
  14371.  
  14372.         if @basecol is not NULL and @joincol is not NULL
  14373.         begin
  14374.             /* Make the piece of predicate pertaining to this key column */
  14375.             set @filtpiece = @table_name + '.' + @basecol + ' = ' + @join_table + '.' + @joincol
  14376.             
  14377.             /* If first time through, initialize clause, else add to it */
  14378.             if @first_piece=0
  14379.             begin
  14380.                 set @first_piece=1
  14381.                 set @filtclause = @filtpiece
  14382.             end
  14383.             else
  14384.                 set @filtclause = @filtclause + ' and ' + @filtpiece
  14385.         end
  14386.         /* move on to the next key */
  14387.         set @keyindex = @keyindex + 1
  14388.         end
  14389.  
  14390.     /* no filter generated due to vertical partitioning */
  14391.     if @first_piece>0
  14392.     begin
  14393.         /* Add the join filter */
  14394.         exec @retcode = dbo.sp_addmergefilter @publication, @article, @filt_name, @join_article, @filtclause, @join_unique
  14395.         if @@ERROR<>0 or @retcode<>0 return (1)
  14396.     end
  14397.  
  14398.     return (0)
  14399.     GO
  14400.  
  14401. exec dbo.sp_MS_marksystemobject sp_MSmakejoinfilter
  14402. go
  14403.  
  14404. raiserror('Creating procedure sp_MSmakeexpandproc', 0,1)
  14405. GO
  14406.  
  14407. create procedure sp_MSmakeexpandproc
  14408.     @pubname        sysname,
  14409.     @filterid       int,
  14410.     @procname       sysname
  14411.     AS
  14412.     /* Declare additional variables */
  14413.     declare @pubid  uniqueidentifier
  14414.     declare @base_nick int
  14415.     declare @join_nick int
  14416.     declare @base_nickstr nvarchar(10)
  14417.     declare @join_nickstr nvarchar(10)
  14418.     declare @filterid_str nvarchar(10)
  14419.     declare @base_objid int
  14420.     declare @join_objid int
  14421.     declare @base_table nvarchar(270)
  14422.     declare    @before_viewname    nvarchar(270)
  14423.     declare @join_table nvarchar(270)
  14424.     declare @base_owner nvarchar(270)
  14425.     declare @join_owner nvarchar(270)
  14426.     declare @join_clause nvarchar(4000)
  14427.     declare @retcode    int
  14428.     declare @must_check int
  14429.     declare @view_type  int
  14430.     declare @guidcolname    nvarchar(270)
  14431.     declare @joinguidname     nvarchar(270)
  14432.     declare @view_objid int
  14433.     declare @view_name  nvarchar(270)
  14434.     declare @cmd_piece  nvarchar(4000)
  14435.  
  14436.     -- Security check
  14437.     if 1 <> is_member('db_owner')
  14438.     begin
  14439.         RAISERROR (15247, 11, -1)
  14440.         return 1
  14441.     end
  14442.  
  14443.     select @pubid = pubid from sysmergepublications where name = @pubname and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  14444.  
  14445.     -- this procedure is to be called by xp_execresultset, so
  14446.     -- we create a temp table, put command pieces into it, and select them out
  14447.     
  14448.     -- create temp table to select the command text out of
  14449.     create table #tempcmd (step int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)
  14450.  
  14451.     /* Figure out base table, join table for this join filter */
  14452.     select @base_nick = art_nickname, @join_nick = join_nickname,
  14453.         @join_clause = join_filterclause
  14454.         from sysmergesubsetfilters where pubid = @pubid and join_filterid = @filterid
  14455.     select @base_objid = objid, @view_type = view_type, @view_objid = sync_objid from sysmergearticles where pubid = @pubid and nickname = @base_nick
  14456.     select @join_objid = objid, @before_viewname = object_name(before_view_objid)  from sysmergearticles where pubid = @pubid and nickname = @join_nick
  14457.     select @base_table = QUOTENAME(name), @base_owner = QUOTENAME(user_name(uid)) from sysobjects where id = @base_objid
  14458.     select @join_table = QUOTENAME(name), @join_owner = QUOTENAME(user_name(uid)) from sysobjects where id = @join_objid
  14459.     select @guidcolname = name from syscolumns where id = @base_objid and 
  14460.             columnproperty (id, name, 'isrowguidcol')=1
  14461.     select @joinguidname = name from syscolumns where id = @join_objid and 
  14462.             columnproperty (id, name, 'isrowguidcol')=1
  14463.     select @view_name = object_name(@view_objid)
  14464.     -- Quote the viewname.  It is made from pub name which may have odd characters.
  14465.     set @view_name = QUOTENAME(@view_name)
  14466.     set @base_nickstr = convert(nvarchar(10), @base_nick)
  14467.     set @join_nickstr = convert(nvarchar(10), @join_nick)
  14468.     set @filterid_str = convert(nvarchar(10), @filterid)
  14469.     
  14470.     set @cmd_piece = 'create procedure dbo.' + @procname + ' 
  14471.         @belong int 
  14472.         AS 
  14473.         declare @command nvarchar(4000), @retcode int  '
  14474.     insert into #tempcmd(cmdtext) values (@cmd_piece)
  14475.     set @cmd_piece = '
  14476.         if @belong = 1
  14477.         begin
  14478.             /* Do a bulk insert to expand #belong */
  14479.             select @command = N''update #belong set flag = ' + @filterid_str + ' where flag < ' + @filterid_str + '''
  14480.             exec @retcode = sp_executesql @command
  14481.             if @@error <> 0 or @retcode <> 0 return 1'
  14482.     insert into #tempcmd(cmdtext) values (@cmd_piece)
  14483.     set @cmd_piece =  'insert into #belong (tablenick, rowguid, flag, skipexpand) select distinct ' + @base_nickstr +
  14484.             ', ' + @base_table + '.rowguidcol, 0, 0 from ' + @base_owner + '.' + @base_table + ', ' +
  14485.             @join_owner + '.' + @join_table + ', #belong b where (' + @join_clause + ') and ' + 
  14486.             @join_table + '.rowguidcol = b.rowguid and b.tablenick = ' + @join_nickstr + ' and skipexpand = 0 '
  14487.        
  14488.     insert into #tempcmd(cmdtext) values (@cmd_piece)
  14489.     set @cmd_piece = '  
  14490.         /* Delete duplicates */
  14491.             select @command = N''delete from #belong where skipexpand = 1 and rowguid in
  14492.                 (select rowguid from #belong where flag = 0)
  14493.             delete from #belong where flag = 0 and rowguid in
  14494.                 (select rowguid from #belong where flag <> 0)''
  14495.             exec @retcode = sp_executesql @command
  14496.             if @@error <> 0 or @retcode <> 0 return 1
  14497.         end '
  14498.     insert into #tempcmd(cmdtext) values (@cmd_piece)
  14499.         
  14500.     /* Will we have to check rows that we add to #notbelong? */
  14501.     if exists (select * from sysmergearticles where pubid = @pubid and nickname = @join_nick and
  14502.         len(subset_filterclause) > 0)
  14503.         set @must_check = 1
  14504.     else if exists (select * from sysmergesubsetfilters where pubid = @pubid and join_filterid = @filterid and
  14505.         join_unique_key <> 1)
  14506.         set @must_check = 1
  14507.     else if not exists (select * from sysmergesubsetfilters where pubid = @pubid and  art_nickname = @base_nick
  14508.             and join_filterid <> @filterid)
  14509.         set @must_check = 0
  14510.     
  14511.     set @cmd_piece = '
  14512.         else 
  14513.         begin
  14514.             select @command = N''update #notbelong set flag = ' + @filterid_str + ' where flag < ' + @filterid_str + ''' 
  14515.             exec @retcode = sp_executesql @command
  14516.             if @@error <> 0 or @retcode <> 0 return 1'
  14517.     insert into #tempcmd(cmdtext) values (@cmd_piece)
  14518.     
  14519.     set @cmd_piece = ' /* Do a bulk insert to expand #notbelong */
  14520.             insert into #notbelong (tablenick, rowguid, flag) select distinct ' + @base_nickstr +
  14521.                 ', ' + @base_table + '.rowguidcol, -1 from ' + @base_owner + '.' + @base_table + ', ' +
  14522.                 @join_owner + '.' + @join_table + ', #notbelong nb where (' + @join_clause + ') and ' + 
  14523.                 @join_table + '.rowguidcol = nb.rowguid and nb.tablenick = ' + @join_nickstr
  14524.                            
  14525.     insert into #tempcmd(cmdtext) values (@cmd_piece)
  14526.     /* Remove duplicates */
  14527.         
  14528.     set @cmd_piece = 'select @command = N''delete from #notbelong where flag = -1 and rowguid in
  14529.         (select rowguid from #notbelong where flag <> -1)''
  14530.         exec @retcode = sp_executesql @command
  14531.         if @@error <> 0 or @retcode <> 0 return 1'
  14532.     insert into #tempcmd(cmdtext) values (@cmd_piece)
  14533.     
  14534.     if @before_viewname  is not null
  14535.     begin
  14536.         set @cmd_piece = '
  14537.             insert into #notbelong (tablenick, rowguid, flag) select distinct ' + @base_nickstr +
  14538.                 ', ' + @base_table + '.rowguidcol, -1 from ' + @base_owner + '.' + @base_table + ', ' +
  14539.                 @before_viewname + ' ' + @join_table + ', #notbelong nb where (' + @join_clause + ') and ' + 
  14540.                 @join_table + '.' + @joinguidname + ' = nb.rowguid and nb.tablenick = ' + @join_nickstr 
  14541.         insert into #tempcmd(cmdtext) values (@cmd_piece)
  14542.             /* Remove duplicates */
  14543.         
  14544.         set @cmd_piece = 'select @command = N''delete from #notbelong where flag = -1 and rowguid in
  14545.                 (select rowguid from #notbelong where flag <> -1)''
  14546.             exec @retcode = sp_executesql @command
  14547.             if @@error <> 0 or @retcode <> 0 return 1'
  14548.         insert into #tempcmd(cmdtext) values (@cmd_piece)
  14549.     end
  14550.     
  14551.     if @must_check = 0
  14552.     begin
  14553.         set @cmd_piece = ' 
  14554.             select @command = N''update #notbelong set flag = 0 where flag = -1 ''
  14555.             exec @retcode = sp_executesql @command
  14556.             if @@error <> 0 or @retcode <> 0 return 1
  14557.         end '
  14558.         insert into #tempcmd(cmdtext) values (@cmd_piece)
  14559.     end
  14560.     else if @view_type = 1
  14561.     begin
  14562.         set @cmd_piece =  '     -- We can do our check with a bulk delete, bulk update
  14563.             select @command = N''delete from #notbelong where flag = -1 and rowguid in
  14564.                 (select ' + @guidcolname + ' from ' + @view_name + ')
  14565.             update #notbelong set flag = 0 where flag = -1''
  14566.             exec @retcode = sp_executesql @command
  14567.             if @@error <> 0 or @retcode <> 0 return 1    
  14568.         end '
  14569.         insert into #tempcmd(cmdtext) values (@cmd_piece)
  14570.     end
  14571.     -- else we don't bother expanding #notbelong for this filter since there are cyclic
  14572.     -- join filters and this is not a unique key join.  The cursored calls to sp_belongs
  14573.     -- are unacceptably slow, and there would still be cases where orphaned rows could occur.
  14574.  
  14575. -- Now we select out the command text pieces in proper order so that our caller,
  14576. -- xp_execresultset will execute the command that creates the stored procedure.
  14577.  
  14578. select cmdtext from #tempcmd order by step
  14579.  
  14580. GO
  14581. exec dbo.sp_MS_marksystemobject sp_MSmakeexpandproc
  14582. go
  14583. grant execute on dbo.sp_MSmakeexpandproc to public
  14584. go
  14585. raiserror('Creating procedure sp_MSdrop_expired_mergesubscription', 0,1)
  14586. GO
  14587.  
  14588. create procedure sp_MSdrop_expired_mergesubscription
  14589. AS
  14590. /*
  14591. ** This stored procedure is to periodically check the status of all the subscriptions 
  14592. ** of every merge publication. If any of them is out-of-date, i.e., has lost contact
  14593. ** with publisher for a certain length of time, we can declare the death of that replica
  14594. ** and cleanup their traces at the publisher side
  14595. */
  14596. declare @subscription_type  int
  14597. declare @sub_type           nvarchar(5)
  14598. declare @publication        sysname
  14599. declare @pubid              uniqueidentifier
  14600. declare @subid              uniqueidentifier
  14601. declare @status             tinyint
  14602. declare @subscriber         sysname
  14603. declare @subscriber_id      int
  14604. declare @subscriber_db      sysname
  14605. declare @publisher             sysname
  14606. declare @publisher_db       sysname
  14607. declare @retention          int  -- in days         
  14608. declare @retcode            smallint
  14609. declare @last_history_logged       datetime
  14610. declare @twice_retention_period       datetime
  14611. declare @min_valid_day                datetime
  14612. declare @distribdb                     sysname
  14613. declare @rpcsrvname                 sysname
  14614. declare @distributor                 sysname
  14615. declare @distproc                     nvarchar(4000)
  14616.  
  14617. /*
  14618. ** Security Check
  14619. */
  14620.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  14621.     IF @@ERROR <> 0 or @retcode <> 0
  14622.         return (1)
  14623.  
  14624. /* we do not check return code here because we can tolerate any failure here */
  14625. exec @retcode = dbo.sp_MScleanup_conflict_table
  14626. if @@ERROR<>0 or @retcode<>0
  14627.     return (1)
  14628.  
  14629. -- Get distributor information for RPC
  14630. exec @retcode = sp_helpdistributor @distributor = @distributor output,
  14631.                                    @distribdb = @distribdb output,
  14632.                                    @rpcsrvname = @rpcsrvname output
  14633. if @@error <> 0 or @retcode <> 0
  14634.     return (1)
  14635.  
  14636. select @distproc = rtrim(@rpcsrvname) + N'.' + @distribdb + N'.' + N'dbo.sp_MSgetlasthistorytimestamp'
  14637.  
  14638.  
  14639. declare PC CURSOR LOCAL FAST_FORWARD for select DISTINCT p.name, p.pubid, p.retention from sysmergepublications p, sysmergesubscriptions s 
  14640.         where s.subid=p.pubid and s.pubid=p.pubid and p.snapshot_ready=1 for read only
  14641.     open PC
  14642.     fetch PC into @publication, @pubid, @retention 
  14643.     
  14644.     WHILE (@@fetch_status <> -1)
  14645.         BEGIN
  14646.             /* Compute the retention period cutoff dates per publication */
  14647.             select @twice_retention_period = dateadd(day, -@retention * 2, getdate())
  14648.             select @min_valid_day = dateadd(day, -@retention, getdate())
  14649.             if @retention is not NULL and @retention > 0
  14650.             begin
  14651.                 -- this is to reomve any user script (file and directory) when following two points fulfills
  14652.                 -- 1. a snapshot has been run to pick it up
  14653.                 -- 2. the snapshot is too old that no new subscription need this file
  14654.                 exec @retcode = sp_MSremove_userscript @pubid
  14655.                 if @@ERROR<>0 or @retcode<>0
  14656.                 begin
  14657.                     close PC
  14658.                     deallocate PC
  14659.                     return (1)
  14660.                 end
  14661.                     declare SC CURSOR LOCAL FAST_FORWARD for select srvid, db_name, subid, status, subscription_type from sysmergesubscriptions where 
  14662.                     pubid = @pubid and pubid<>subid for read only
  14663.                    open SC
  14664.                 fetch SC into @subscriber_id, @subscriber_db, @subid, @status, @subscription_type
  14665.                 WHILE (@@fetch_status <> -1)
  14666.                     BEGIN
  14667.                         select @subscriber=srvname from master..sysservers where srvid=@subscriber_id
  14668.                         if @subscription_type = 0 select @sub_type = 'push' else select @sub_type = 'pull'
  14669.                         select @publisher = publisher, @publisher_db = publisher_db from sysmergepublications where pubid = @pubid
  14670.  
  14671.                         exec @retcode = @distproc 
  14672.                             @publisher = @publisher,
  14673.                             @publisher_db = @publisher_db,
  14674.                             @publication = @publication,
  14675.                             @subscriber = @subscriber,
  14676.                             @subscriber_db = @subscriber_db,
  14677.                             @last_history_logged = @last_history_logged OUTPUT
  14678.                            if @retcode <>0 or @@ERROR<>0
  14679.                                goto FAILURE
  14680.     
  14681.                         if @status <> 2 and @last_history_logged < @min_valid_day
  14682.                         begin
  14683.                             exec @retcode = dbo.sp_dropmergesubscription  
  14684.                                     @publication = @publication,
  14685.                                     @subscriber = @subscriber,
  14686.                                     @subscriber_db = @subscriber_db,
  14687.                                     @subscription_type = @sub_type  
  14688.                                if @retcode <>0 or @@ERROR<>0
  14689.                                 goto FAILURE
  14690.                             raiserror(14157, 10, -1, @subscriber, @publication) 
  14691.                         end
  14692.  
  14693.                         /* 
  14694.                         ** Remove global subscriptions after twice the retention period has passed
  14695.                         ** This is to prevent global subscribers from being resurrected.
  14696.                         */
  14697.                         if @last_history_logged < @twice_retention_period 
  14698.                         begin
  14699.                             delete from sysmergesubscriptions where subid = @subid --delete the row in sysmergesubscription
  14700.                                if @@ERROR<>0
  14701.                                 goto FAILURE
  14702.                             delete from MSmerge_replinfo where repid = @subid
  14703.                             if @@ERROR<>0
  14704.                                 goto FAILURE
  14705.                         end     
  14706.                         fetch SC into @subscriber_id, @subscriber_db, @subid, @status, @subscription_type
  14707.                     END
  14708.                 CLOSE SC
  14709.                 DEALLOCATE SC
  14710.             end
  14711.             fetch PC into @publication, @pubid, @retention
  14712.         END
  14713.     CLOSE PC
  14714.     DEALLOCATE PC
  14715.     return (0)
  14716.     
  14717. FAILURE:
  14718.     close SC
  14719.     deallocate SC
  14720.     close PC
  14721.     deallocate PC
  14722.     return (1)
  14723.  
  14724. GO
  14725. exec dbo.sp_MS_marksystemobject sp_MSdrop_expired_mergesubscription
  14726. go
  14727.  
  14728. raiserror('Creating procedure sp_MScleanup_metadata', 0,1)
  14729. GO
  14730.  
  14731. create procedure sp_MScleanup_metadata
  14732. @pubid            uniqueidentifier
  14733. AS
  14734. declare @retcode                 int
  14735. declare @truncate_flag          int 
  14736. declare @pubid2                    uniqueidentifier
  14737. declare @artid                  uniqueidentifier
  14738. declare @schematype             int
  14739. declare @schemaversion          int
  14740. declare @schemaguid             uniqueidentifier
  14741. declare @schematext             nvarchar(2000)
  14742. declare @rcount                    int
  14743.  
  14744. set nocount on
  14745. /*
  14746. ** Security Check
  14747. */
  14748. EXEC @retcode = dbo.sp_MSreplcheck_publish
  14749. IF @@ERROR <> 0 or @retcode <> 0
  14750.     return (1)
  14751.     
  14752. if sessionproperty('replication_agent') <> 0
  14753.     begin
  14754.     -- called from Merge Agent.  If we are republishing, must add this command for
  14755.     -- any publications which are republishing data from the original publication.
  14756.  
  14757.     declare #per_publication CURSOR LOCAL FAST_FORWARD for select pubid
  14758.         from sysmergepublications p where LOWER(publisher)=LOWER(@@SERVERNAME) and 
  14759.                 publisher_db=db_name() and 
  14760.             exists (select * from sysmergearticles a1, sysmergearticles a2 where
  14761.                     a1.pubid = p.pubid and a2.pubid = @pubid and a1.objid = a2.objid)
  14762.     open #per_publication        
  14763.     fetch #per_publication into @pubid2
  14764.     while @@fetch_status<>-1
  14765.         begin
  14766.            select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
  14767.         if (@schemaversion is NULL)
  14768.                set @schemaversion = 1
  14769.         set @schemaguid = newid()
  14770.            set @artid = newid()
  14771.            set @schematype = 16 /* metadata cleanup */
  14772.            select @schematext = 'exec dbo.sp_MScleanup_metadata '+ '''' + convert(nchar(36),@pubid2) + '''' 
  14773.         exec @retcode=sp_MSinsertschemachange @pubid2, @artid, @schemaversion, @schemaguid, @schematype, @schematext
  14774.         if @@ERROR<>0 or @retcode<>0 
  14775.             begin
  14776.             close #per_publication
  14777.             deallocate #per_publication
  14778.             return (1)
  14779.           
  14780.             end
  14781.     
  14782.         fetch next from #per_publication into @pubid2
  14783.         end
  14784.     close #per_publication
  14785.     deallocate #per_publication
  14786.       end
  14787. else
  14788.       begin
  14789.       -- should be nested call from sp_mergecleanupmetadata and we should be the
  14790.       -- publisher of this publication
  14791.     if @pubid is not null and not exists (select * from sysmergepublications where
  14792.         LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name() and pubid = @pubid)
  14793.         begin
  14794.         return (1)
  14795.         end
  14796.       end
  14797.  
  14798. -- Figure out whether there are any publications which prevent us from truncating the tables
  14799. if @pubid is null
  14800.     begin
  14801.     if exists (select * from sysmergepublications where
  14802.         LOWER(publisher)<> LOWER(@@SERVERNAME) or publisher_db<>db_name())
  14803.         set @truncate_flag = 0
  14804.     else
  14805.         set @truncate_flag = 1
  14806.     end
  14807. else
  14808.     begin
  14809.     if exists (select * from sysmergepublications p where p.pubid <> @pubid and
  14810.         (LOWER(publisher)<> LOWER(@@SERVERNAME) or publisher_db<>db_name() or
  14811.         not exists (select * from sysmergearticles a1, sysmergearticles a2 where
  14812.             a1.pubid = p.pubid and a2.pubid = @pubid and a1.objid = a2.objid)))
  14813.         set @truncate_flag = 0
  14814.     else
  14815.         set @truncate_flag = 1    
  14816.     end
  14817.  
  14818.  
  14819. if @pubid is not null
  14820.     begin
  14821.         /* If there are any inprocess generations inform user that queisce did not succeed - reinit required  */
  14822.         if exists (select top 1 guidsrc from dbo.MSmerge_genhistory h
  14823.             where    guidlocal='00000000-0000-0000-0000-000000000000'  -- incomplete gen
  14824.                 and generation not in (select gen_cur from sysmergearticles)  -- not a local incomplete gen
  14825.                 and coldate in (select login_time from master..sysprocesses)  -- not a gen that currently receives replica updates from another db
  14826.                 and h.art_nick in (select nickname from sysmergearticles where pubid = @pubid)) -- generations relevant to current publication 
  14827.             begin
  14828.                 declare @dbname sysname
  14829.                 set @dbname = db_name()
  14830.                 RAISERROR(21504, 16, -1, @@servername, @dbname)
  14831.                 return (1)
  14832.             end
  14833.     end
  14834. if @truncate_flag = 1
  14835.     begin
  14836.     truncate table MSmerge_contents
  14837.     truncate table MSmerge_tombstone
  14838.     truncate table MSmerge_genhistory
  14839.     update sysmergearticles set gen_cur = NULL
  14840.     update MSmerge_replinfo set recgen = NULL, recguid = NULL, sentgen = NULL, sentguid = NULL 
  14841.     end
  14842. else
  14843.     begin
  14844.     -- set up temp table of article nicknames that we delete for
  14845.     create table #artnicks (nickname int)
  14846.     if @pubid is null
  14847.         begin
  14848.         -- insert pubids for all local publications
  14849.         insert into #artnicks select distinct nickname from sysmergearticles where
  14850.             pubid in (select pubid from sysmergepublications where
  14851.                 LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name())
  14852.         end
  14853.     else
  14854.         begin
  14855.         insert into #artnicks select distinct nickname from sysmergearticles where
  14856.             pubid = @pubid
  14857.         end
  14858.     
  14859.         
  14860.     -- do deletions in batches of 5000 to avoid excessive log growth
  14861.     
  14862.     set rowcount 5000
  14863.     set @rcount = 1
  14864.     while @rcount > 0
  14865.         begin
  14866.         set @rcount = 0
  14867.  
  14868.         -- update our cumulative count of rows deleted in this pass with each table
  14869.         delete MSmerge_contents WITH (PAGLOCK) from MSmerge_contents where tablenick in (select nickname from #artnicks)
  14870.         set @rcount = @@rowcount + @rcount
  14871.         delete MSmerge_tombstone WITH (PAGLOCK) from MSmerge_tombstone where tablenick in (select nickname from #artnicks)
  14872.         set @rcount = @@rowcount + @rcount
  14873.         delete MSmerge_genhistory WITH (PAGLOCK) from MSmerge_genhistory where art_nick in (select nickname from #artnicks)
  14874.         set @rcount = @@rowcount + @rcount
  14875.         end
  14876.     
  14877.     update sysmergearticles set gen_cur = NULL where nickname in (select nickname from #artnicks)
  14878.  
  14879.     if @pubid is not null
  14880.         update MSmerge_replinfo set recgen = NULL, recguid = NULL, sentgen = NULL, sentguid = NULL 
  14881.             where repid in ( select subid from sysmergesubscriptions where pubid = @pubid)
  14882.     else
  14883.         update MSmerge_replinfo set recgen = NULL, recguid = NULL, sentgen = NULL, sentguid = NULL 
  14884.             where repid in ( select subid from sysmergesubscriptions s, sysmergepublications p
  14885.                 where s.pubid = p.pubid and LOWER(p.publisher)=LOWER(@@SERVERNAME) and p.publisher_db=db_name())
  14886.     
  14887.     drop table #artnicks
  14888.     dbcc dbreindex ( MSmerge_contents )
  14889.     end
  14890.  
  14891. execute @retcode = dbo.sp_MSmakegeneration 
  14892. if @@ERROR <> 0 or @retcode <> 0
  14893.     return (1)
  14894. return 0
  14895.  
  14896. GO
  14897. exec dbo.sp_MS_marksystemobject sp_MScleanup_metadata
  14898. go
  14899. grant execute on dbo.sp_MScleanup_metadata to public
  14900. go
  14901.  
  14902.  
  14903. raiserror('Creating procedure sp_helpmergecleanupwait', 0,1)
  14904. GO
  14905. create procedure sp_helpmergecleanupwait
  14906. AS
  14907.     declare @retcode int
  14908.     
  14909.     /*
  14910.     ** Security Check
  14911.     */
  14912.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  14913.     IF @@ERROR <> 0 or @retcode <> 0
  14914.         return (1)
  14915.     
  14916.     -- Tell user if we don't think we are waiting!
  14917.     if not exists (select * from sysmergesubscriptions where status = 7)
  14918.         raiserror(21507, 0,1)
  14919.  
  14920.     if exists (select * from sysmergepublications p, sysmergesubscriptions s
  14921.             where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name() and
  14922.                 p.pubid = s.pubid and s.status = 7 and s.subid <> s.pubid)
  14923.         begin
  14924.         raiserror(21509, 0,1)
  14925.         select publication, srvid, db_name from sysmergesubscriptions where status = 7
  14926.         end
  14927.     else if exists (select * from MSmerge_genhistory, master..sysprocesses where guidlocal = '00000000-0000-0000-0000-000000000000' and
  14928.             coldate = login_time)
  14929.         begin
  14930.         raiserror(21508, 0,1)
  14931.         select hostname, program_name from master..sysprocesses where login_time in
  14932.             (select coldate from MSmerge_genhistory where guidlocal = '00000000-0000-0000-0000-000000000000')
  14933.         end
  14934.     else
  14935.         exec sp_MSquiescecheck
  14936.     
  14937. GO
  14938.  
  14939. grant execute on sp_helpmergecleanupwait to public
  14940. GO
  14941.  
  14942.  
  14943. exec dbo.sp_MS_marksystemobject sp_helpmergecleanupwait
  14944. go
  14945. raiserror('Creating procedure sp_MSquiescecheck', 0,1)
  14946. GO
  14947.  
  14948. create procedure sp_MSquiescecheck
  14949. AS
  14950.     declare @mysrvid        int
  14951.     declare @pubid            uniqueidentifier
  14952.     declare @retcode        int
  14953.  
  14954.     set nocount on
  14955.  
  14956.     -- If we are not waiting to quiesce, do nothing more
  14957.     if not exists (select * from sysmergesubscriptions where status = 7)
  14958.         return 0
  14959.  
  14960.     -- If we publish to any republishers who are still waiting to
  14961.     -- quiesce (status = 7) then just return for now.
  14962.     if exists (select * from sysmergepublications p, sysmergesubscriptions s
  14963.             where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name() and
  14964.                 p.pubid = s.pubid and s.status = 7 and s.subid <> s.pubid)
  14965.         return 0
  14966.  
  14967.     -- Set publication status to inactive for all publications I have that are participating
  14968.     -- in the metadata cleanup.
  14969.     update sysmergepublications set status = 0 where LOWER(publisher)=LOWER(@@SERVERNAME) and
  14970.         publisher_db=db_name() and pubid in
  14971.             (select a1.pubid from sysmergearticles a1, sysmergearticles a2, sysmergesubscriptions s
  14972.                 where a1.objid = a2.objid and a2.pubid = s.pubid and s.status = 7)
  14973.                 
  14974.     -- If there are any open generations with more than 0 rows, we must still wait
  14975.     if exists (select * from MSmerge_genhistory gh where guidlocal = '00000000-0000-0000-0000-000000000000' and
  14976.                 generation not in (select gen_cur from sysmergearticles) 
  14977.                     and coldate in (select login_time from master..sysprocesses)) 
  14978.         return 0
  14979.  
  14980.     
  14981.  
  14982.     -- Am I the top-level publisher or just a republisher?
  14983.     set @mysrvid = 0
  14984.     select @mysrvid = srvid from master..sysservers where srvname = @@SERVERNAME
  14985.     if exists (select * from sysmergesubscriptions s where srvid = @mysrvid and
  14986.         db_name = db_name() and status = 7 and subid <> pubid)
  14987.         begin
  14988.         -- I am not the top level publisher.  Just set my status & let it propagate up.
  14989.         update sysmergesubscriptions set status = 8 where
  14990.             srvid = @mysrvid and db_name = db_name() and status = 7
  14991.         return 0
  14992.         end
  14993.     else
  14994.         begin
  14995.         -- I am the top level publisher!  Start getting rid of that old metadata!
  14996.         select @pubid = pubid from sysmergesubscriptions where srvid = @mysrvid and
  14997.             db_name = db_name() and status = 7
  14998.         exec @retcode = dbo.sp_MScompletecleanup @pubid
  14999.         return @retcode
  15000.         end
  15001.             
  15002. GO
  15003. exec dbo.sp_MS_marksystemobject sp_MSquiescecheck
  15004. go
  15005.  
  15006.  
  15007. raiserror('Creating procedure sp_mergepreparecleanup', 0,1)
  15008. GO
  15009.  
  15010. create procedure sp_mergepreparecleanup
  15011.     @publication    sysname
  15012. AS
  15013. declare @pubid            uniqueidentifier
  15014. declare @retcode        int
  15015.  
  15016. declare @schematype             int
  15017. declare @schematext             nvarchar(2000)
  15018. /*
  15019. ** Security Check
  15020. */
  15021. EXEC @retcode = dbo.sp_MSreplcheck_publish
  15022. IF @@ERROR <> 0 or @retcode <> 0
  15023.     return (1)
  15024.  
  15025. set nocount on
  15026.  
  15027. /* Validate the publication  */
  15028. select @pubid = pubid from sysmergepublications 
  15029.         where name = @publication and 
  15030.         LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name()
  15031.         
  15032. if @pubid is NULL
  15033.         begin
  15034.            raiserror (20026, 11, -1, @publication)
  15035.         return (1)
  15036.         end
  15037. if exists (select * from sysmergearticles a1, sysmergearticles a2
  15038.      where a1.pubid = @pubid and a2.objid = a1.objid and
  15039.         a2.pubid not in (select pubid from sysmergepublications where
  15040.         LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name()))
  15041.         begin
  15042.         raiserror(21272, 16, -1, @publication)
  15043.         return (1)
  15044.         end
  15045.  
  15046. exec @retcode=sp_MSBumpupCompLevel @pubid, 40 
  15047. if @@ERROR<>0 or @retcode<>0        
  15048.     return (1)
  15049.         
  15050. -- stop local updates by creating the quiesce triggers
  15051. exec @retcode = sp_MSquiescetriggerson
  15052.  
  15053. -- use publisher row in sysmergesubscriptions to store datetime we started quiesce sequence
  15054. update sysmergesubscriptions set last_sync_date = getdate() where pubid = @pubid and subid = @pubid
  15055.  
  15056. -- insert a schema change that will cause subscribers and republishers to prepare for cleanup
  15057. set @schematype = 17 /* metadata cleanup */
  15058. set @schematext = 'exec dbo.sp_MSpreparecleanup '
  15059. exec sp_MSpropagateschematorepubs @pubid, @schematext, @schematype
  15060.        
  15061. GO
  15062.  
  15063. exec dbo.sp_MS_marksystemobject sp_mergepreparecleanup
  15064. go
  15065. grant execute on dbo.sp_mergepreparecleanup to public
  15066. go
  15067.  
  15068. raiserror('Creating procedure sp_MSpreparecleanup', 0,1)
  15069. GO
  15070.  
  15071. create procedure sp_MSpreparecleanup
  15072.     @pubid            uniqueidentifier
  15073. AS
  15074. declare @retcode         int
  15075. declare @schematype             int
  15076. declare @schematext             nvarchar(2000)
  15077.  
  15078. -- security check. this proc is called on the subscriber. Hence needs dbo sysadmin check
  15079. EXEC @retcode = dbo.sp_MSreplcheck_subscribe
  15080. IF @@ERROR <> 0 or @retcode <> 0
  15081.     return (1)
  15082.     
  15083. -- This should only be invoked by the merge agent as it processes schema changes
  15084. if sessionproperty('replication_agent') = 0
  15085.     return (1)
  15086.  
  15087. set nocount on
  15088.  
  15089. exec @retcode=sp_MSBumpupCompLevel @pubid, 40 
  15090. if @@ERROR<>0 or @retcode<>0        
  15091.     return (1)
  15092.  
  15093. -- stop local updates by creating the quiesce triggers
  15094. exec @retcode = sp_MSquiescetriggerson
  15095.  
  15096. -- If we are a republisher, propagate the schema change on to our subscribers
  15097. set @schematype = 17 /* prepare cleanup */
  15098. select @schematext = 'exec dbo.sp_MSpreparecleanup '
  15099. exec sp_MSpropagateschematorepubs @pubid, @schematext, @schematype
  15100. return (0)
  15101.  
  15102. GO
  15103.  
  15104. exec dbo.sp_MS_marksystemobject sp_MSpreparecleanup
  15105. go
  15106. grant execute on dbo.sp_MSpreparecleanup to public
  15107. go
  15108.  
  15109. raiserror('Creating procedure sp_MSquiescetriggerson', 0,1)
  15110. GO
  15111.  
  15112. create procedure sp_MSquiescetriggerson
  15113. AS
  15114. declare @cmd nvarchar(4000)
  15115.  
  15116. if not exists (select * from sysobjects where xtype = N'TR' and name = 'MS_mergequiescetrigger')
  15117.     begin
  15118.     set @cmd = 'create trigger MS_mergequiescetrigger on MSmerge_contents for UPDATE, INSERT, DELETE 
  15119.     NOT FOR REPLICATION AS
  15120.     if sessionproperty(''replication_agent'') = 0
  15121.         begin
  15122.         -- Raise an appropriate error
  15123.         RAISERROR(21510, 11, -1)
  15124.         rollback tran
  15125.         end'
  15126.     execute (@cmd)
  15127.     end
  15128.  
  15129. if not exists (select * from sysobjects where xtype = N'TR' and name = 'MS_mergequiescetrigger2')
  15130. begin
  15131.     set @cmd = 'create trigger MS_mergequiescetrigger2 on MSmerge_tombstone for UPDATE, INSERT, DELETE 
  15132.     NOT FOR REPLICATION AS
  15133.     if sessionproperty(''replication_agent'') = 0
  15134.         begin
  15135.         -- Raise an appropriate error
  15136.         RAISERROR(21510, 11, -1)
  15137.         rollback tran
  15138.         end'
  15139.     execute (@cmd)    
  15140.     end
  15141. GO
  15142. exec dbo.sp_MS_marksystemobject sp_MSquiescetriggerson
  15143. go
  15144.  
  15145.  
  15146. raiserror('Creating procedure sp_MSquiescetriggersoff', 0,1)
  15147. GO
  15148.  
  15149. create procedure sp_MSquiescetriggersoff
  15150. AS
  15151.     if exists (select * from sysobjects where xtype = N'TR' and name = 'MS_mergequiescetrigger')
  15152.         drop trigger MS_mergequiescetrigger
  15153.     if exists (select * from sysobjects where xtype = N'TR' and name = 'MS_mergequiescetrigger2')
  15154.         drop trigger MS_mergequiescetrigger2
  15155.  
  15156. GO
  15157. exec dbo.sp_MS_marksystemobject sp_MSquiescetriggersoff
  15158. go
  15159. raiserror('Creating procedure sp_MSquiesceforcleanup', 0,1)
  15160. GO
  15161. create procedure sp_MSquiesceforcleanup    
  15162.     @pubid     uniqueidentifier
  15163. AS
  15164.     declare @schematype     int
  15165.     declare @schematext        nvarchar(4000)
  15166.     declare @mysrvid                int
  15167.     declare @retcode int
  15168.  
  15169.     set nocount on
  15170.  
  15171.     -- security check
  15172.     -- this proc is called on the subscriber through a schema change
  15173.     exec @retcode = dbo.sp_MSreplcheck_subscribe
  15174.     if @retcode <> 0 or @@error <> 0
  15175.         return 1
  15176.  
  15177.     set @mysrvid = 0
  15178.     select @mysrvid = srvid from master..sysservers where srvname = @@SERVERNAME
  15179.  
  15180.     -- @pubid is normally the publication I subscribe to, get the pubid's of what I republish
  15181.     create table #mypubids(pubid uniqueidentifier)
  15182.  
  15183.     insert into #mypubids (pubid) select distinct p.pubid from sysmergepublications p,
  15184.             sysmergearticles a1, sysmergearticles a2
  15185.         where a1.pubid = @pubid and a1.objid = a2.objid and p.pubid = a2.pubid and
  15186.              LOWER(p.publisher)=LOWER(@@SERVERNAME) and p.publisher_db=db_name()
  15187.  
  15188.     -- If I don't republish, then I am done and ready
  15189.     if @@ROWCOUNT = 0
  15190.         begin
  15191.         drop table #mypubids
  15192.         
  15193.         -- REPLICA_STATUS_ReadyForCleanup         = 0x0008
  15194.         update sysmergesubscriptions set status = 8 where pubid = @pubid and
  15195.             db_name = db_name() and srvid = @mysrvid
  15196.         
  15197.         return 0
  15198.         end
  15199.  
  15200.     -- set my status to QuiesceRequested
  15201.     -- REPLICA_STATUS_QuieseRequested    = 0x0007,
  15202.     update sysmergesubscriptions set status = 7 where pubid = @pubid and
  15203.             db_name = db_name() and srvid = @mysrvid
  15204.     update sysmergesubscriptions set status = 7 where pubid in (select pubid from #mypubids) and
  15205.         db_name = db_name() and srvid = @mysrvid
  15206.  
  15207.     -- update status for my republishing subscribers
  15208.     update sysmergesubscriptions set status = 7 where pubid in (select pubid from #mypubids)
  15209.         and subid in (select s1.subid from sysmergesubscriptions s1, sysmergesubscriptions s2
  15210.                 where s1.pubid in (select pubid from #mypubids) and s1.srvid = s2.srvid and
  15211.                 s1.db_name = s2.db_name and s2.subid = s2.pubid and s2.status = 1)
  15212.  
  15213.     -- check if any of my subscribers republish
  15214.     if @@ROWCOUNT = 0
  15215.         begin
  15216.         -- If none of my subscribers are republishers, then I just
  15217.         -- set my publications' status to unavailable and set
  15218.         -- set my replica status as ReadyForCleanup
  15219.  
  15220.         update sysmergepublications set status = 0 where pubid in (select pubid from #mypubids)
  15221.         -- I may have ongoing merges call the quiescecheck routine to try and set my status
  15222.         exec @retcode = sp_MSquiescecheck                    
  15223.         end
  15224.     else
  15225.         begin
  15226.         -- propagate the schema change on to my subscribers
  15227.         set @schematype = 19  -- SCHEMA_TYPE_QUIESCE            = 19
  15228.         set @schematext = 'exec dbo.sp_MSquiesceforcleanup '
  15229.         exec sp_MSpropagateschematorepubs @pubid, @schematext, @schematype
  15230.         end
  15231.     drop table #mypubids
  15232. GO
  15233.  
  15234. grant execute on dbo.sp_MSquiesceforcleanup to public
  15235. go
  15236.  
  15237. exec dbo.sp_MS_marksystemobject sp_MSquiesceforcleanup
  15238. go
  15239.  
  15240. raiserror('Creating procedure sp_mergecompletecleanup', 0,1)
  15241. GO
  15242.  
  15243. create procedure sp_mergecompletecleanup
  15244.     @publication        sysname
  15245. AS
  15246. declare @pubid            uniqueidentifier
  15247. declare @retcode        int
  15248.  
  15249. set nocount on
  15250.  
  15251. /*
  15252. ** Security Check
  15253. */
  15254. EXEC @retcode = dbo.sp_MSreplcheck_publish
  15255. IF @@ERROR <> 0 or @retcode <> 0
  15256.     return (1)
  15257. /* make sure current database is enabled for merge replication */
  15258. exec @retcode=dbo.sp_MSCheckmergereplication
  15259. if @@ERROR<>0 or @retcode<>0
  15260.     return (1)
  15261.     
  15262.  
  15263. /* Validate the publication  */
  15264. select @pubid = pubid from sysmergepublications 
  15265.         where name = @publication and 
  15266.         LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name()
  15267.         
  15268. if @pubid is NULL
  15269.         begin
  15270.                raiserror (20026, 11, -1, @publication)
  15271.             return (1)
  15272.         end
  15273. -- Make sure we are at the top-level publisher
  15274.  
  15275. if exists (select * from sysmergearticles a1, sysmergearticles a2
  15276.      where a1.pubid = @pubid and a2.objid = a1.objid and
  15277.         a2.pubid not in (select pubid from sysmergepublications where
  15278.         LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name()))
  15279.         begin
  15280.         raiserror(21272, 16, -1, @publication)
  15281.         return (1)
  15282.         end
  15283.         
  15284. -- If user never id sp_mergepreparecleanup then inform them of their error.
  15285. if not exists(select * from sysmergeschemachange where schematype = 17)
  15286.     begin
  15287.     raiserror(21506, 0, 1)
  15288.     return (1)
  15289.     end
  15290.  
  15291. -- Use sp_MSquiesceforcleanup to propagate schema, etc.
  15292. exec @retcode = sp_MSquiesceforcleanup @pubid
  15293. if @@ERROR<>0 or @retcode<>0
  15294.     return (1)
  15295.  
  15296.     
  15297. GO
  15298. exec dbo.sp_MS_marksystemobject sp_mergecompletecleanup
  15299. go
  15300.  
  15301. grant execute on dbo.sp_mergecompletecleanup to public
  15302. go
  15303.  
  15304. raiserror('Creating procedure sp_MScompletecleanup', 0,1)
  15305. GO
  15306.  
  15307. create procedure sp_MScompletecleanup
  15308. @pubid            uniqueidentifier
  15309. AS
  15310. declare @retcode         int
  15311. declare @otherpubs  int 
  15312. declare @pubid2        uniqueidentifier
  15313. declare @artid                  uniqueidentifier
  15314. declare @schematype             int
  15315. declare @schemaversion          int
  15316. declare @schemaguid             uniqueidentifier
  15317. declare @schematext             nvarchar(2000)
  15318. declare @rcount                        int
  15319. declare @dtprepare                datetime
  15320. declare @cutoffgen                int
  15321. declare @mysrvid                int
  15322. declare @toplevel                int
  15323.  
  15324. set nocount on
  15325.  
  15326. if exists (select * from sysmergepublications where pubid = @pubid and
  15327.         LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name())
  15328.     set @toplevel = 1
  15329. else
  15330.     set @toplevel = 0
  15331.     
  15332. /*
  15333. ** Security Check
  15334. */
  15335. EXEC @retcode = dbo.sp_MSreplcheck_publish
  15336. IF @@ERROR <> 0 or @retcode <> 0
  15337.     return (1)
  15338.  
  15339. -- Figure out whether there are any other publications which make us copy additional rows
  15340. set @otherpubs = 0
  15341.  
  15342. if exists (select * from sysmergearticles a1 where a1.objid not in
  15343.                 (select objid from sysmergearticles where pubid = @pubid))
  15344.     set @otherpubs = 1
  15345.  
  15346. if @otherpubs = 1 or @toplevel = 1
  15347.     begin
  15348.     -- create some temp tables to preserve part of MSmerge_contents
  15349.     create table #contents (tablenick int NOT NULL,
  15350.                 rowguid            uniqueidentifier rowguidcol   NOT NULL,
  15351.                 generation        int                    NOT NULL,
  15352.                 partchangegen    int                    NULL,
  15353.                 joinchangegen    int                    NULL,
  15354.                 lineage            varbinary(249)        NOT NULL,
  15355.                 colv1            varbinary(2048)        NULL)
  15356.  
  15357.     create table #tombstone (rowguid            uniqueidentifier rowguidcol NOT NULL,
  15358.                 tablenick        int                NOT NULL,
  15359.                 type            tinyint            NOT NULL,
  15360.                 lineage            varbinary(249)    NOT NULL,
  15361.                 generation        int                NOT NULL,
  15362.                 reason            nvarchar(255)    NOT NULL)
  15363.  
  15364.     end
  15365.     
  15366.     -- propagate the schema change on to our subscribers
  15367.        set @schematype = 18 /* metadata cleanup */
  15368.     select @schematext = 'exec dbo.sp_MScompletecleanup '
  15369.     exec sp_MSpropagateschematorepubs @pubid, @schematext, @schematype
  15370.  
  15371. if @toplevel = 1
  15372.       begin                
  15373.      /* Get the timestamp when we did the prepareforcleanup */
  15374.     select @dtprepare = last_sync_date from sysmergesubscriptions where pubid = @pubid and
  15375.             subid = @pubid
  15376.     -- Copy some generations from contents and tombstone into temptables
  15377.     select @cutoffgen = min(generation) from MSmerge_genhistory where coldate > @dtprepare
  15378.     
  15379.     if @otherpubs = 1
  15380.         begin
  15381.         insert into #contents (tablenick, rowguid, generation, partchangegen, joinchangegen, lineage, colv1)
  15382.                 select tablenick, rowguid, 0,
  15383.                         case when partchangegen < @cutoffgen then NULL else 0 end,
  15384.                         case when joinchangegen < @cutoffgen then NULL else 0 end,
  15385.                 lineage, colv1 from MSmerge_contents where generation >= @cutoffgen and tablenick
  15386.                     in (select nickname from sysmergearticles where pubid = @pubid)
  15387.         end
  15388.     else
  15389.         begin
  15390.         -- leaving out join to sysmergearticles should help performance
  15391.         insert into #contents (tablenick, rowguid, generation, partchangegen, joinchangegen, lineage, colv1)
  15392.                 select tablenick, rowguid, 0,
  15393.                         case when partchangegen < @cutoffgen then NULL else 0 end,
  15394.                         case when joinchangegen < @cutoffgen then NULL else 0 end,
  15395.                 lineage, colv1 from MSmerge_contents where generation >= @cutoffgen 
  15396.         end
  15397.                 
  15398.     if @otherpubs = 1
  15399.         begin
  15400.         insert into #tombstone (rowguid, tablenick, type, lineage, generation, reason)
  15401.             select rowguid, tablenick, type, lineage, 0, reason
  15402.             from MSmerge_tombstone where generation >= @cutoffgen and tablenick
  15403.                 in (select nickname from sysmergearticles where pubid = @pubid)
  15404.         end
  15405.     else
  15406.         begin
  15407.         insert into #tombstone (rowguid, tablenick, type, lineage, generation, reason)
  15408.             select rowguid, tablenick, type, lineage, 0, reason
  15409.             from MSmerge_tombstone where generation >= @cutoffgen    
  15410.         end
  15411.      end
  15412.  
  15413. if @otherpubs = 1
  15414.     begin
  15415.     insert into #contents (tablenick, rowguid, generation, partchangegen, joinchangegen, lineage, colv1)
  15416.         select * from MSmerge_contents where tablenick not in
  15417.             (select nickname from sysmergearticles where pubid = @pubid)
  15418.     insert into #tombstone (rowguid, tablenick, type, lineage, generation, reason)
  15419.         select * from MSmerge_tombstone where tablenick not in
  15420.             (select nickname from sysmergearticles where pubid = @pubid)
  15421.     end
  15422.     
  15423. truncate table MSmerge_contents
  15424. truncate table MSmerge_tombstone
  15425.  
  15426. if @otherpubs = 0
  15427.     begin
  15428.     truncate table MSmerge_genhistory
  15429.     update sysmergearticles set gen_cur = NULL
  15430.     update MSmerge_replinfo set recgen = NULL, recguid = NULL, sentgen = NULL, sentguid = NULL 
  15431.     end
  15432. else
  15433.     begin
  15434.     -- set up temp table of article nicknames that we delete for
  15435.     create table #artnicks (nickname int)
  15436.     insert into #artnicks select distinct nickname from sysmergearticles where
  15437.             pubid = @pubid
  15438.             
  15439.     -- do deletions in batches of 5000 to avoid excessive log growth
  15440.     set rowcount 5000
  15441.     set @rcount = 1
  15442.     while @rcount > 0
  15443.         begin
  15444.         set @rcount = 0
  15445.         delete MSmerge_genhistory WITH (PAGLOCK) from MSmerge_genhistory where art_nick in (select nickname from #artnicks)
  15446.         set @rcount = @@rowcount
  15447.         end
  15448.     
  15449.     update sysmergearticles set gen_cur = NULL where nickname in (select nickname from #artnicks)
  15450.  
  15451.     update MSmerge_replinfo set recgen = NULL, recguid = NULL, sentgen = NULL, sentguid = NULL 
  15452.             where repid in ( select subid from sysmergesubscriptions where pubid = @pubid)
  15453.     
  15454.     drop table #artnicks
  15455.     end
  15456.  
  15457. -- Remove triggers now so we can reinsert the rows we saved from contents
  15458.     execute @retcode = sp_MSquiescetriggersoff
  15459.  
  15460. if @toplevel = 1 or @otherpubs = 1
  15461.     begin
  15462.     -- Put back the rows from #contents and #tombstone
  15463.     insert into MSmerge_contents (tablenick, rowguid, generation, partchangegen, joinchangegen, lineage, colv1)
  15464.         select * from #contents
  15465.     insert into MSmerge_tombstone (rowguid, tablenick, type, lineage, generation, reason)
  15466.         select * from #tombstone
  15467.     end
  15468.  
  15469. -- Mark publications as active but snapshot expired
  15470. update sysmergepublications set status = 1, snapshot_ready = 3 where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name() and 
  15471.         pubid in (select a1.pubid from sysmergearticles a1, sysmergearticles a2 where
  15472.                     a2.pubid = @pubid and a1.objid = a2.objid)
  15473.  
  15474. -- Set our subscriber status back to 1
  15475. set @mysrvid = 0
  15476. select @mysrvid = srvid from master..sysservers where srvname = @@SERVERNAME
  15477. update sysmergesubscriptions set status = 1 where srvid = @mysrvid and db_name = db_name() and
  15478.     pubid in (select a1.pubid from sysmergearticles a1, sysmergearticles a2 where a1.objid = a2.objid 
  15479.                 and a2.pubid = @pubid)
  15480. -- update subscriptions rows that still say status of ReadyForCleanup
  15481. update sysmergesubscriptions set status = 1 where status = 8
  15482.                 
  15483. execute @retcode = dbo.sp_MSmakegeneration 
  15484. if @@ERROR <> 0 or @retcode <> 0
  15485.     return (1)
  15486. return 0
  15487.  
  15488. GO
  15489. exec dbo.sp_MS_marksystemobject sp_MScompletecleanup
  15490. go
  15491.  
  15492. raiserror('Creating procedure sp_MSpropagateschematorepubs', 0,1)
  15493. GO
  15494.  
  15495. create procedure sp_MSpropagateschematorepubs
  15496.     @pubid        uniqueidentifier,
  15497.     @schema_text    nvarchar(4000),
  15498.     @schema_type int
  15499. AS
  15500. declare @pubid2            uniqueidentifier
  15501. declare @artid            uniqueidentifier
  15502. declare @fulltext        nvarchar(4000)
  15503. declare @retcode        int
  15504. declare @schemaversion          int
  15505. declare @schemaguid             uniqueidentifier
  15506. declare @schematext             nvarchar(2000)
  15507.  
  15508. set nocount on
  15509.  
  15510.     -- Find republications and add the same schema change
  15511.     declare #per_publication CURSOR LOCAL FAST_FORWARD for select pubid
  15512.         from sysmergepublications p where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name() and 
  15513.             exists (select * from sysmergearticles a1, sysmergearticles a2 where
  15514.                     a1.pubid = p.pubid and a2.pubid = @pubid and a1.objid = a2.objid)
  15515.     open #per_publication        
  15516.     fetch #per_publication into @pubid2
  15517.     while @@fetch_status<>-1
  15518.         begin
  15519.            select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
  15520.         if (@schemaversion is NULL)
  15521.                set @schemaversion = 1
  15522.         set @schemaguid = newid()
  15523.            set @artid = newid()
  15524.            select @fulltext = @schema_text + ' ''' + convert(nchar(36),@pubid2) + '''' 
  15525.         exec @retcode=sp_MSinsertschemachange @pubid2, @artid, @schemaversion, @schemaguid, @schema_type, @fulltext
  15526.         if @@ERROR<>0 or @retcode<>0 
  15527.             begin
  15528.             close #per_publication
  15529.             deallocate #per_publication
  15530.             return (1)
  15531.           
  15532.             end
  15533.         fetch next from #per_publication into @pubid2
  15534.         end
  15535.     close #per_publication
  15536.     deallocate #per_publication
  15537.     return (0)
  15538. GO
  15539. exec dbo.sp_MS_marksystemobject sp_MSpropagateschematorepubs
  15540. go
  15541.  
  15542.  
  15543. raiserror('Creating procedure sp_mergecleanupmetadata', 0,1)
  15544. GO
  15545.  
  15546. create procedure sp_mergecleanupmetadata
  15547.     @publication        sysname = '%',
  15548.     @reinitialize_subscriber    nvarchar(5) = 'true'
  15549. AS
  15550. declare @pubid                    uniqueidentifier
  15551. declare @retcode                int
  15552. declare @pubname                  sysname
  15553. declare @snapshot_ready         int
  15554. declare @make_generation         int
  15555. declare @artid                  uniqueidentifier
  15556. declare @schematype             int
  15557. declare @schemaversion          int
  15558. declare @schemaguid             uniqueidentifier
  15559. declare @schematext             nvarchar(2000)
  15560.  
  15561. set @make_generation = 0
  15562. /*
  15563. ** Security Check
  15564. */
  15565. EXEC @retcode = dbo.sp_MSreplcheck_publish
  15566. IF @@ERROR <> 0 or @retcode <> 0
  15567.     return (1)
  15568. /* make sure current database is enabled for merge replication */
  15569. exec @retcode=dbo.sp_MSCheckmergereplication
  15570. if @@ERROR<>0 or @retcode<>0
  15571.     return (1)
  15572.     
  15573.  
  15574. /* Validate the publication name if one is provided */
  15575. if @publication <> '%'
  15576.     begin
  15577.         select @pubid = pubid from sysmergepublications 
  15578.             where name = @publication
  15579.         if @pubid is NULL
  15580.             begin
  15581.                 raiserror (20026, 11, -1, @publication)
  15582.                 return (1)
  15583.             end
  15584.     end
  15585.  
  15586. if not exists (select * from sysobjects where name='sysmergearticles')
  15587.     return (1)
  15588.     
  15589. begin TRAN
  15590. save TRAN cleanupmetadata
  15591. declare #per_publication CURSOR LOCAL FAST_FORWARD for select pubid
  15592.     from sysmergepublications where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name() and name like @publication
  15593. open #per_publication
  15594. fetch #per_publication into @pubid
  15595. while @@fetch_status<>-1
  15596. begin
  15597.     select @pubname=name, @snapshot_ready=snapshot_ready from sysmergepublications where pubid=@pubid
  15598.     if @publication <> '%' and exists (select * from sysmergearticles where pubid<>@pubid and objid in
  15599.         (select objid from sysmergearticles where pubid=@pubid))
  15600.     begin
  15601.         raiserror(21272, 16, -1, @pubname)
  15602.         goto FAILURE
  15603.     end
  15604.  
  15605.     /* Only do this when snapshot has been ran before this operation */
  15606.     if @snapshot_ready>0
  15607.     begin
  15608.         /* If there are any inprocess generations defer the cleanup of metadata */
  15609.         if exists (select top 1 guidsrc from dbo.MSmerge_genhistory h
  15610.             where    guidlocal='00000000-0000-0000-0000-000000000000'  -- incomplete gen
  15611.                 and generation not in (select gen_cur from sysmergearticles)  -- not a local incomplete gen
  15612.                 and coldate in (select login_time from master..sysprocesses)  -- not a gen that currently receives replica updates from another db
  15613.                 and h.art_nick in (select nickname from sysmergearticles where pubid = @pubid)) -- generations relevant to current publication 
  15614.             begin
  15615.                 RAISERROR(21503, 16, -1)
  15616.                 close #per_publication
  15617.                 deallocate #per_publication
  15618.                 goto FAILURE
  15619.             end
  15620.         if LOWER(@reinitialize_subscriber collate SQL_Latin1_General_CP1_CS_AS)='true'        
  15621.         begin
  15622.             -- backward-comp-level is bump'd up by calling this stored procedure            
  15623.             exec @retcode = sp_MSreinitmergepublication @pubname
  15624.             if @@ERROR<>0 or @retcode<>0
  15625.             begin
  15626.                 close #per_publication
  15627.                 deallocate #per_publication
  15628.                 goto FAILURE
  15629.             end
  15630.  
  15631.             update sysmergepublications set snapshot_ready=2 where pubid=@pubid
  15632.             if @@ERROR<>0
  15633.             begin
  15634.                 close #per_publication
  15635.                 deallocate #per_publication
  15636.                 goto FAILURE
  15637.             end
  15638.         end
  15639.         else
  15640.         begin
  15641.             raiserror(21355, 10, -1,@publication)
  15642.             exec @retcode=sp_MSBumpupCompLevel @pubid, 30 --SP2 subscribers support this, but do not propagate
  15643.             if @@ERROR<>0 or @retcode<>0
  15644.             begin
  15645.                 close #per_publication
  15646.                 deallocate #per_publication
  15647.                 goto FAILURE
  15648.             end
  15649.  
  15650.             select @schemaversion = schemaversion from sysmergeschemachange
  15651.             if (@schemaversion is NULL)
  15652.             set @schemaversion = 1
  15653.             else
  15654.                 select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
  15655.             set @schemaguid = newid()
  15656.             set @artid = newid()
  15657.             set @schematype = 16 /* metadata cleanup */
  15658.             select @schematext = 'exec dbo.sp_MScleanup_metadata '+ '''' + convert(nchar(36),@pubid) + '''' 
  15659.             exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
  15660.             if @@ERROR<>0 or @retcode<>0 
  15661.             begin
  15662.                 close #per_publication
  15663.                 deallocate #per_publication
  15664.                 goto FAILURE            
  15665.             end
  15666.             
  15667.         end
  15668.     end
  15669.     set @make_generation = 1
  15670.     fetch next from #per_publication into @pubid
  15671. end
  15672. close #per_publication
  15673. deallocate #per_publication
  15674. COMMIT TRAN
  15675.  
  15676. if @publication = '%'
  15677.     begin
  15678.         set @pubid = NULL
  15679.     end
  15680. else
  15681.     begin
  15682.         select @pubid = pubid from sysmergepublications 
  15683.             where name = @publication
  15684.     end
  15685.  
  15686.     exec @retcode = dbo.sp_MScleanup_metadata @pubid
  15687.     if @@ERROR <> 0 or @retcode <> 0
  15688.            goto FAILURE
  15689. if @make_generation = 1
  15690.     begin
  15691.         execute @retcode = dbo.sp_MSmakegeneration 
  15692.         if @@ERROR <> 0 or @retcode <> 0
  15693.                goto FAILURE
  15694.     end
  15695. return (0)
  15696. FAILURE:
  15697.     if @@TRANCOUNT > 0
  15698.     begin
  15699.         ROLLBACK TRANSACTION cleanupmetadata
  15700.         COMMIT TRANSACTION
  15701.     end
  15702.     return (1)
  15703.  
  15704. GO
  15705.  
  15706. exec dbo.sp_MS_marksystemobject sp_mergecleanupmetadata
  15707. go
  15708. grant execute on dbo.sp_mergecleanupmetadata to public
  15709. go
  15710.  
  15711.  
  15712. raiserror('Creating procedure sp_MScleanup_conflict_table', 0,1)
  15713. GO
  15714. /*
  15715. ** This stored procedure is to periodically check and cleanup all the conflict entries 
  15716. ** in conflict tables that has been there longer than the value of conflict_retention in
  15717. ** days. 
  15718. */
  15719.  
  15720. create procedure sp_MScleanup_conflict_table
  15721. AS
  15722. BEGIN
  15723.     declare    @retcode            int
  15724.     declare @pubid                uniqueidentifier
  15725.     declare    @conflict_retention    int
  15726.             ,@conflict_table    sysname
  15727.             ,@cmd                nvarchar(4000)
  15728.             ,@tranpubid            int
  15729.  
  15730.     /*
  15731.     ** Security Check
  15732.     */
  15733.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  15734.     IF @@ERROR <> 0 or @retcode <> 0
  15735.         return (1)
  15736.  
  15737.     --
  15738.     -- merge cleanup
  15739.     --
  15740.     if exists (select * from sysobjects where name = 'sysmergepublications')
  15741.     begin
  15742.         declare PC CURSOR LOCAL FAST_FORWARD for select DISTINCT pubid, conflict_retention
  15743.             from sysmergepublications where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name() and conflict_retention>0
  15744.         open PC
  15745.         fetch PC into @pubid, @conflict_retention
  15746.         while (@@fetch_status<>-1)
  15747.         begin
  15748.             exec @retcode = sp_MScleanup_conflict @pubid, @conflict_retention
  15749.             if @@ERROR<>0 or @retcode<>0
  15750.             begin
  15751.                 close PC
  15752.                 deallocate PC
  15753.                 return (1)
  15754.             end
  15755.             fetch next from PC into  @pubid, @conflict_retention
  15756.         end
  15757.         close PC
  15758.         deallocate PC
  15759.     end
  15760.  
  15761.     --
  15762.     -- tran cleanup
  15763.     --
  15764.     if (EXISTS (select * from sysobjects where name = 'syspublications'))
  15765.     begin
  15766.         --
  15767.         -- do for each conflict table in each publication
  15768.         --
  15769.         declare hCftTab cursor LOCAL FAST_FORWARD for
  15770.             select a.pubid, a.conflict_retention, OBJECT_NAME(c.conflict_tableid)
  15771.             from (syspublications as a join sysarticles as b on a.pubid = b.pubid)
  15772.                 join sysarticleupdates as c on c.artid = b.artid and c.pubid = b.pubid
  15773.             where a.allow_queued_tran = 1 and a.conflict_retention>0
  15774.  
  15775.         open hCftTab
  15776.         fetch hCftTab into @tranpubid, @conflict_retention, @conflict_table
  15777.         while (@@fetch_status != -1)
  15778.         begin
  15779.             --
  15780.             -- delete the expired messages
  15781.             --
  15782.             select @cmd = 'delete ' + quotename(master.dbo.fn_MSgensqescstr(@conflict_table)) collate database_default + 
  15783.                 ' where datediff(dd, getdate(), insertdate) > ' + 
  15784.                 cast(@conflict_retention as nvarchar(10)) +
  15785.                 ' and pubid = ' + cast(@tranpubid as nvarchar(10))
  15786.  
  15787.             execute (@cmd)
  15788.             if (@@error != 0)
  15789.             begin
  15790.                 close hCftTab
  15791.                 deallocate hCftTab
  15792.                 return 1                
  15793.             end
  15794.                 
  15795.             --
  15796.             -- Get next conflict table to clean
  15797.             --
  15798.             fetch hCftTab into @tranpubid, @conflict_retention, @conflict_table
  15799.         end
  15800.  
  15801.         --
  15802.         -- close cursor
  15803.         --
  15804.         close hCftTab
  15805.         deallocate hCftTab
  15806.     end
  15807.  
  15808.     --
  15809.     -- all done 
  15810.     --
  15811.     return 0
  15812. END
  15813. GO
  15814. exec dbo.sp_MS_marksystemobject sp_MScleanup_conflict_table
  15815. go
  15816.  
  15817. raiserror('Creating procedure sp_validatemergesubscription', 0,1)
  15818. GO
  15819.  
  15820. CREATE PROCEDURE sp_validatemergesubscription
  15821.     (@publication            sysname,
  15822.      @subscriber            sysname,
  15823.      @subscriber_db            sysname,
  15824.      @level                    tinyint
  15825.      ) AS
  15826.      
  15827.     declare @subscriber_srvid        int
  15828.     declare @retcode                int
  15829.     declare @pubid                    uniqueidentifier
  15830.     /*
  15831.     ** Security Check
  15832.     */
  15833.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  15834.     IF @@ERROR <> 0 or @retcode <> 0
  15835.         return (1)
  15836.  
  15837.     /* make sure current database is enabled for merge replication */
  15838.     exec @retcode=dbo.sp_MSCheckmergereplication
  15839.     if @@ERROR<>0 or @retcode<>0
  15840.         return (1)
  15841.  
  15842.     select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber)
  15843.  
  15844.     select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  15845.     if @pubid is NULL
  15846.         begin
  15847.             raiserror (20026, 16, -1, @publication)
  15848.             return (1)
  15849.         end
  15850.     if @level <1 or @level > 3
  15851.         begin
  15852.             raiserror(21184, 16, -1, '@level', '1', '2','3')
  15853.             return (1)
  15854.         end
  15855.  
  15856.     if not exists (select * from sysmergesubscriptions where pubid=@pubid and db_name=@subscriber_db and srvid=@subscriber_srvid)
  15857.         begin
  15858.             raiserror(14055, 16, -1)
  15859.             return (1)
  15860.         end
  15861.  
  15862.     update sysmergesubscriptions set validation_level=@level where pubid=@pubid and db_name=@subscriber_db and srvid=@subscriber_srvid
  15863.     if @@ERROR<>0
  15864.         return (1)
  15865.     return (0)
  15866.  
  15867. go
  15868. exec dbo.sp_MS_marksystemobject sp_validatemergesubscription
  15869. go
  15870. grant exec on dbo.sp_validatemergesubscription to public
  15871. go
  15872.  
  15873. raiserror('Creating procedure sp_validatemergepublication', 0,1)
  15874. GO
  15875.  
  15876. CREATE PROCEDURE sp_validatemergepublication
  15877.     (@publication            sysname,
  15878.      @level                    tinyint
  15879.      ) AS
  15880.      
  15881.     declare @artid                  uniqueidentifier
  15882.     declare @schematype             int
  15883.     declare @schemaversion          int
  15884.     declare @schemaguid             uniqueidentifier
  15885.     declare @schematext                nvarchar
  15886.     declare @retcode                int
  15887.     declare @pubid                    uniqueidentifier
  15888.     /*
  15889.     ** Security Check
  15890.     */
  15891.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  15892.     IF @@ERROR <> 0 or @retcode <> 0
  15893.         return (1)
  15894.  
  15895.     /* make sure current database is enabled for merge replication */
  15896.     exec @retcode=dbo.sp_MSCheckmergereplication
  15897.     if @@ERROR<>0 or @retcode<>0
  15898.         return (1)
  15899.  
  15900.     select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  15901.     if @pubid is NULL
  15902.         begin
  15903.             raiserror (20026, 16, -1, @publication)
  15904.             return (1)
  15905.         end
  15906.     if @level <1 or @level > 3
  15907.         begin
  15908.             raiserror(21184, 16, -1, '@level', '1', '2','3')
  15909.             return (1)
  15910.         end
  15911.  
  15912.     raiserror(21356, 10, -1, @publication)
  15913.     exec @retcode=sp_MSBumpupCompLevel @pubid, 30 
  15914.     if @@ERROR<>0 or @retcode<>0        
  15915.         return (1)
  15916.  
  15917.     select @schemaversion = schemaversion from sysmergeschemachange
  15918.     if (@schemaversion is NULL)
  15919.         set @schemaversion = 1
  15920.     else
  15921.         select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
  15922.         set @schemaguid = newid()
  15923.         set @artid = newid()
  15924.         set @schematype = 66 /* publication wide validation */
  15925.         select @schematext = convert(nvarchar, @level)        
  15926.         exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
  15927.         if @@ERROR<>0 or @retcode<>0
  15928.             return (1)
  15929.     return (0)
  15930. go
  15931. exec dbo.sp_MS_marksystemobject sp_validatemergepublication
  15932. go
  15933. grant exec on dbo.sp_validatemergepublication to public
  15934. go
  15935.  
  15936. raiserror('Creating procedure sp_MScleanup_conflict', 0,1)
  15937. GO
  15938.  
  15939. create procedure sp_MScleanup_conflict
  15940. @pubid                    uniqueidentifier,
  15941. @conflict_retention    int = NULL
  15942. AS
  15943.     declare @pubname            sysname
  15944.     declare @valid_date            datetime
  15945.     declare @conflict_table        sysname
  15946.     declare @conflict_id        int
  15947.     declare @retention_string        nvarchar(100)
  15948.     declare @pubidstr            nvarchar(100)
  15949.     declare @retcode            int
  15950.     
  15951.     --if no conflict_retention value is specified, query local table and find out.
  15952.     if @conflict_retention is NULL
  15953.         select @conflict_retention=conflict_retention from sysmergepublications where pubid=@pubid
  15954.  
  15955.     --do not do any cleanup if conflict retention value is 0
  15956.     else if @conflict_retention = 0
  15957.         return (0)
  15958.  
  15959.     select @pubname=name from sysmergepublications where pubid=@pubid
  15960.     select @pubidstr = convert(nvarchar(40), @pubid)
  15961.     select @valid_date = dateadd(day, -@conflict_retention, getdate())
  15962.     select @retention_string = convert(nvarchar, @conflict_retention)
  15963.     /*
  15964.     ** Security Check
  15965.     */
  15966.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  15967.     IF @@ERROR <> 0 or @retcode <> 0
  15968.         return (1)
  15969.  
  15970.  
  15971.     if exists (select name from syscolumns where name='create_time' and id = object_id('MSmerge_delete_conflicts'))
  15972.     begin
  15973.         delete from MSmerge_delete_conflicts where create_time < @valid_date and pubid=@pubid
  15974.         if @@ERROR<>0
  15975.             return (1)
  15976.     end
  15977.     
  15978.     declare AC CURSOR LOCAL FAST_FORWARD for select conflict_table from sysmergearticles where pubid=@pubid
  15979.     open AC
  15980.     fetch AC into @conflict_table
  15981.     while (@@fetch_status<>-1)
  15982.     begin
  15983.         if @conflict_table is NOT null
  15984.             begin
  15985.  
  15986.             select @conflict_id = object_id(@conflict_table)
  15987.             select @conflict_table=QUOTENAME(@conflict_table)
  15988.             /*
  15989.             ** Upgrade conflict table so that it can get cleaned up later on
  15990.             */
  15991.             if @conflict_id is not NULL and not exists (select name from syscolumns where name='MSrepl_create_time' and id=@conflict_id)
  15992.                     begin
  15993.                         exec ('alter table ' + @conflict_table + ' add MSrepl_create_time datetime not NULL default getdate() ')
  15994.                         if @@ERROR<>0
  15995.                             goto FAILURE
  15996.                     end
  15997.  
  15998.             if @conflict_id is not NULL and @retention_string is not NULL and exists (select name from syscolumns where name='MSrepl_create_time' and id=@conflict_id)
  15999.                     begin
  16000.                         exec ('delete from ' + @conflict_table + ' where datediff(dd, MSrepl_create_time, getdate()) > ' + @retention_string + ' and pubid = ''' + @pubidstr + '''')
  16001.                         if @@ERROR<>0
  16002.                             goto FAILURE
  16003.                     end
  16004.             end
  16005.         fetch next from AC into @conflict_table
  16006.     end
  16007.     close AC
  16008.     deallocate AC
  16009.     return (0)
  16010. FAILURE:
  16011.     close AC
  16012.     deallocate AC
  16013.     return (1)
  16014. GO
  16015. exec dbo.sp_MS_marksystemobject sp_MScleanup_conflict
  16016. go
  16017.  
  16018.  
  16019. raiserror('Creating procedure sp_generatefilters', 0,1)
  16020. GO
  16021.  
  16022. create procedure sp_generatefilters
  16023.     @publication                sysname
  16024.     AS
  16025.     /* Declare  a few variables */
  16026.     declare @pubid  uniqueidentifier
  16027.     declare @art_name sysname
  16028.     declare @object_id  int
  16029.     declare @join_objid int
  16030.     declare @retcode int
  16031.     declare @join_unique int
  16032.     declare @distance int
  16033.     
  16034.     /*
  16035.     ** Security Check
  16036.     */
  16037.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  16038.     IF @@ERROR <> 0 or @retcode <> 0
  16039.         return (1)
  16040.  
  16041.     /*
  16042.     ** Parameter Check: @publication.
  16043.     ** The @publication id cannot be NULL and must conform to the rules
  16044.     ** for identifiers.
  16045.     */   
  16046.         
  16047.     if @publication is NULL
  16048.         begin
  16049.             raiserror (14043, 16, -1, '@publication')
  16050.             return (1)
  16051.         end
  16052.     /*
  16053.     ** Get the pubid and make sure the publication exists
  16054.     */
  16055.     select @pubid = pubid from sysmergepublications 
  16056.         where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  16057.     if @pubid is NULL
  16058.         begin
  16059.             raiserror (20026, 16, -1, @publication)
  16060.             return (1)
  16061.         end
  16062.  
  16063.     /* Set up some temp tables to help keep track of what to process */
  16064.     create table #filtered (object_id int NOT NULL, distance int NOT NULL)
  16065.     create table #unfiltered (object_id int NOT NULL, art_name sysname collate database_default not null)
  16066.  
  16067.     /* Do initial population of temp tables */
  16068.     insert into #filtered (object_id, distance) select objid, 0 from sysmergearticles where
  16069.         pubid = @pubid and len(subset_filterclause) > 0
  16070.     insert into #unfiltered (object_id, art_name) select objid, name from sysmergearticles
  16071.         where pubid = @pubid and objid not in (select object_id from #filtered)
  16072.  
  16073.     /* remove self-referencing tables from #unfiltered as we should not try to filter them */
  16074.     delete from #unfiltered where object_id in
  16075.             (select rkeyid from sysreferences where rkeyid = fkeyid)
  16076.     select @distance = min(distance) from #filtered f, sysreferences r, #unfiltered u where
  16077.         (f.object_id = r.rkeyid and r.fkeyid = u.object_id) or
  16078.         (u.object_id = r.rkeyid and r.fkeyid = f.object_id)
  16079.         
  16080.     /* Look for something in sysreferences to add a join filter for */
  16081.     select @join_unique = 1, @object_id = fkeyid, @join_objid = rkeyid, @art_name = art_name
  16082.         from sysreferences r, #unfiltered u where r.fkeyid = u.object_id and
  16083.         r.rkeyid in (select object_id from #filtered where distance = @distance) 
  16084.  
  16085.     if @art_name is null
  16086.         select  @join_unique = 0, @object_id = rkeyid, @join_objid = fkeyid, @art_name = art_name
  16087.             from sysreferences r, #unfiltered u where r.rkeyid = u.object_id and
  16088.             r.fkeyid in (select object_id from #filtered where distance = @distance) 
  16089.     while @art_name is not null
  16090.         begin
  16091.         /* Make the join filter corresponding to this relationship */
  16092.         exec @retcode=sp_MSmakejoinfilter @publication, @art_name, @object_id, @join_objid, @join_unique
  16093.         if @@ERROR<>0 or @retcode<>0 return (1)
  16094.         /* Move row from #unfiltered to #filtered */
  16095.         insert into #filtered (object_id, distance) values (@object_id, @distance + 1)
  16096.         delete from #unfiltered where object_id = @object_id
  16097.         
  16098.         /* See if any more that can be added */
  16099.         select @distance = min(distance) from #filtered f, sysreferences r, #unfiltered u where
  16100.             (f.object_id = r.rkeyid and r.fkeyid = u.object_id) or
  16101.             (u.object_id = r.rkeyid and r.fkeyid = f.object_id)
  16102.         set @art_name = NULL
  16103.         select @join_unique = 1, @object_id = fkeyid, @join_objid = rkeyid, @art_name = art_name
  16104.             from sysreferences r, #unfiltered u where r.fkeyid = u.object_id and
  16105.             r.rkeyid in (select object_id from #filtered where distance = @distance) 
  16106.         if @art_name is null
  16107.             select  @join_unique = 0, @object_id = rkeyid, @join_objid = fkeyid, @art_name = art_name
  16108.                 from sysreferences r, #unfiltered u where r.rkeyid = u.object_id and
  16109.                 r.fkeyid in (select object_id from #filtered where distance = @distance) 
  16110.         end
  16111.     return (0)
  16112. go
  16113.             
  16114. exec dbo.sp_MS_marksystemobject sp_generatefilters
  16115. go
  16116.  
  16117. grant execute on dbo.sp_generatefilters to public
  16118. go
  16119.  
  16120. /*
  16121. ** Name :       sp_MShelpmergeconflictcounts
  16122. ** Description: This sp returns the count of conflicts (from MSmerge_delete_conflicts and 
  16123. **              each conflict table) in each publication. Results can optionally be filtered
  16124. **                to include only a single publication. Results are always ordered by article
  16125. **                name. Only articles with non-zero conflict counts are returned.
  16126. ** Parameters:  1. Publication Name( sysname; default '%'==ALL PUBLICATIONS)
  16127. ** Output Result Set has the following structure 
  16128. **  ----------------------------------------------------------------------------------
  16129. **      Name                Datatype                Description
  16130. **  ----------------------------------------------------------------------------------
  16131. **  a. article                (sysname)            Article name
  16132. **  b. conflict_table        (sysname)            Associated conflict table
  16133. **  c. guidcolname            (sysname)            Article's rowguidcol name
  16134. **  d. centralized_conflicts(integer)            Centralized (1) or Decentralized (0) 
  16135. **                                                conflicts specified by the article
  16136. **  e. conflict_ucount        (integer)           Count of (update) conflicts in the 
  16137. **                                                conflict table for this article
  16138. **  f. conflicts_dcount        (integer)           Count of (delete) conflicts in the 
  16139. **                                                MSmerge_delete_conflicts table for this article
  16140. */
  16141. raiserror('Creating procedure sp_MShelpmergeconflictcounts', 0,1)
  16142. GO
  16143. create procedure sp_MShelpmergeconflictcounts ( 
  16144.     @publication_name sysname = '%' ,
  16145.     @publisher        sysname = NULL,
  16146.     @publisher_db    sysname = NULL)
  16147. as 
  16148. begin
  16149.  
  16150.     set nocount on 
  16151.  
  16152.     declare    @aname         sysname
  16153.     declare    @cmd         nvarchar(2000) 
  16154.     declare    @conflict_table sysname 
  16155.     declare    @count         integer
  16156.     declare @pubid          uniqueidentifier
  16157.     declare @pubidstr       nvarchar(38)
  16158.     declare @retcode    int
  16159.  
  16160.     -- Security check
  16161.     if 1 <> is_member('db_owner') and
  16162.        (1 <> is_member('replmonitor') or is_member('replmonitor') is null)
  16163.     begin    
  16164.         RAISERROR (15247, 11, -1)
  16165.         return (1)
  16166.     end
  16167.  
  16168.     if @publisher IS NULL
  16169.         select @publisher = @@SERVERNAME
  16170.         
  16171.     if @publisher_db IS NULL
  16172.         select @publisher_db = db_name()
  16173.  
  16174.     if @publication_name <> '%'
  16175.         begin
  16176.             /*
  16177.             ** Parameter Check:  @publication.
  16178.             ** Make sure that the publication exists.
  16179.             */
  16180.             select @pubid = pubid from sysmergepublications 
  16181.                 where name = @publication_name and 
  16182.                     LOWER(publisher) = LOWER(@publisher) and
  16183.                     publisher_db = @publisher_db
  16184.             if @pubid IS NULL
  16185.                 BEGIN
  16186.                     RAISERROR (20026, 16, -1, @publication_name)
  16187.                     RETURN (1)
  16188.                 END
  16189.             set @pubidstr = '''' + convert(nchar(36), @pubid) + '''' 
  16190.         end
  16191.  
  16192.     -- make sure current db has merge publishing tables (true on both pub and sub)
  16193.     if not exists ( select * from sysobjects where name = 'sysmergearticles')
  16194.     begin
  16195.         raiserror( 18757, 16, -1 )
  16196.         return(1)
  16197.     end
  16198.  
  16199.     -- allow null conflict table name to handle case where there are delete conflicts but no update conflicts
  16200.     create table #result_list ( article sysname collate database_default, source_object sysname collate database_default, conflict_table sysname collate database_default null, guidcolname sysname collate database_default, centralized_conflicts integer, conflicts_ucount integer, conflicts_dcount integer )
  16201.     create table #conflict_list ( article_name sysname collate database_default, conflicts_ucount integer, conflicts_dcount integer )
  16202.     create table #update_list ( article_name sysname collate database_default, conflicts_ucount integer )
  16203.  
  16204.     -- get delete counts
  16205.     if ( @publication_name = '%' )
  16206.         declare hCdcount CURSOR LOCAL FAST_FORWARD fast_forward for 
  16207.             select distinct a.name 
  16208.                 from MSmerge_delete_conflicts d
  16209.                 inner join sysmergepublications p on p.pubid = d.pubid
  16210.                 inner join sysmergearticles a on a.pubid = p.pubid and a.nickname = d.tablenick
  16211.     else
  16212.         declare hCdcount CURSOR LOCAL FAST_FORWARD fast_forward for 
  16213.             select distinct a.name 
  16214.                 from MSmerge_delete_conflicts d
  16215.                 inner join sysmergepublications p on p.pubid = d.pubid
  16216.                 inner join sysmergearticles a on a.pubid = p.pubid and a.nickname = d.tablenick
  16217.                 where p.pubid = @pubid
  16218.     open hCdcount
  16219.     fetch hCdcount into @aname
  16220.     while ( @@fetch_status <> -1 )
  16221.     begin
  16222.  
  16223.         select @cmd = 'select N''' + @aname + ''', 0, count(*) 
  16224.                 from MSmerge_delete_conflicts d
  16225.                     inner join sysmergepublications p on p.pubid = d.pubid
  16226.                     inner join sysmergearticles a on a.pubid = p.pubid and a.nickname = d.tablenick
  16227.                 where a.name = @aname'
  16228.  
  16229.         if ( @publication_name <> '%' ) 
  16230.             select @cmd = @cmd + ' and p.pubid = ' + @pubidstr
  16231.  
  16232.         insert #conflict_list ( article_name, conflicts_ucount, conflicts_dcount )
  16233.             exec @retcode= dbo.sp_executesql @cmd, N'@aname sysname', @aname = @aname
  16234.         if @@error<>0 and @retcode<>0
  16235.         begin
  16236.             close hCdcount
  16237.             deallocate hCdcount
  16238.             return 1
  16239.         end
  16240.  
  16241.         fetch hCdcount into @aname
  16242.     end
  16243.     close hCdcount
  16244.     deallocate hCdcount
  16245.  
  16246.     -- get update counts
  16247.     if ( @publication_name = '%' )
  16248.         declare hCucount CURSOR LOCAL FAST_FORWARD fast_forward for 
  16249.             select distinct a.name, a.conflict_table
  16250.                 from sysmergepublications p
  16251.                 inner join sysmergearticles a on a.pubid = p.pubid
  16252.             where a.conflict_table is not null
  16253.     else
  16254.         declare hCucount CURSOR LOCAL FAST_FORWARD fast_forward for 
  16255.             select distinct a.name, a.conflict_table
  16256.                 from sysmergepublications p
  16257.                 inner join sysmergearticles a on a.pubid = p.pubid
  16258.             where a.conflict_table is not null
  16259.                   and p.pubid = @pubid
  16260.     open hCucount
  16261.     fetch hCucount into @aname, @conflict_table
  16262.     while ( @@fetch_status <> -1 )
  16263.     begin
  16264.         select @cmd = N'select N''' + @aname + N''', count(*) from ' + QUOTENAME( @conflict_table ) + N' ct inner join sysmergepublications p on p.pubid = ct.pubid '
  16265.  
  16266.         if ( @publication_name <> '%' ) 
  16267.             select @cmd = @cmd + ' where p.name = @publication_name '
  16268.         insert #update_list ( article_name, conflicts_ucount )
  16269.             exec @retcode= dbo.sp_executesql @cmd, N'@publication_name sysname', @publication_name = @publication_name
  16270.         if @@error<>0 and @retcode<>0
  16271.         begin
  16272.             close hCucount
  16273.             deallocate hCucount
  16274.             return 1
  16275.         end
  16276.  
  16277.         fetch hCucount into @aname, @conflict_table
  16278.     end
  16279.     close hCucount
  16280.     deallocate hCucount
  16281.  
  16282.     update #conflict_list set conflicts_ucount = isnull( ul.conflicts_ucount, 0 )
  16283.         from #conflict_list cl
  16284.         inner join #update_list ul on ul.article_name = cl.article_name
  16285.  
  16286.     delete #update_list 
  16287.         from #update_list ul 
  16288.         inner join #conflict_list cl on ul.article_name = cl.article_name
  16289.  
  16290.     insert #conflict_list
  16291.         select *, 0 from #update_list where conflicts_ucount > 0
  16292.  
  16293.     drop table #update_list
  16294.     select @cmd = N'select distinct t.article_name, N'''' + quotename(user_name( o.uid )) + ''.'' + quotename(o.name) + '''',' + ' a.conflict_table, c.name, p.centralized_conflicts, t.conflicts_ucount, t.conflicts_dcount
  16295.             from #conflict_list t
  16296.                 inner join sysmergearticles a on a.name = t.article_name
  16297.                 inner join sysmergepublications p on p.pubid = a.pubid
  16298.                 inner join sysobjects o on o.id = a.objid 
  16299.                 inner join syscolumns c on c.id = o.id and ColumnProperty (o.id, c.name, ''IsRowGuidCol'') = 1
  16300.             where (t.conflicts_ucount > 0 or t.conflicts_dcount > 0) and a.conflict_table is NOT NULL and p.name like N''' + @publication_name + ''''
  16301.     insert #result_list
  16302.         exec ( @cmd )        
  16303.     if ( @@error <> 0 )
  16304.         return (1)
  16305.  
  16306.     drop table #conflict_list
  16307.  
  16308.     select * from #result_list
  16309.     drop table #result_list
  16310.  
  16311. return (0)
  16312. end
  16313. go
  16314. exec dbo.sp_MS_marksystemobject sp_MShelpmergeconflictcounts
  16315. go
  16316. grant execute on dbo.sp_MShelpmergeconflictcounts to public
  16317. go
  16318.  
  16319. /*
  16320. ** Name :       sp_MShelpmergeconflictpublications
  16321. ** Description: This sp returns a list of merge publications in the current database 
  16322. **                that may have conflicts.
  16323. **                Results are always ordered by publication name.
  16324. ** Output Result Set has the following structure 
  16325. **  ----------------------------------------------------------------------------------
  16326. **      Name                Datatype                Description
  16327. **  ----------------------------------------------------------------------------------
  16328. **  a. publication            (sysname)                Publication name
  16329. **    b. merge_pub_id            (uniqueidentifier)        Merge publication id
  16330. */
  16331. raiserror('Creating procedure sp_MShelpmergeconflictcpublications', 0,1)
  16332. GO
  16333.  
  16334. create procedure sp_MShelpmergeconflictpublications
  16335. as 
  16336. begin
  16337.  
  16338.     set nocount on 
  16339.     declare @retcode int
  16340.     /*
  16341.     ** Security Check
  16342.     */
  16343.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  16344.     IF @@ERROR <> 0 or @retcode <> 0
  16345.         return (1)
  16346.  
  16347.     declare @dbname sysname, @cmd nvarchar(200)
  16348.     set @dbname = db_name()
  16349.  
  16350.     -- make sure current db has merge publishing tables (true on both pub and sub)
  16351.     if not exists ( select * from sysobjects where name = 'sysmergepublications')
  16352.     begin
  16353.         raiserror( 18757, 16, -1 )
  16354.         return(1)
  16355.     end
  16356.  
  16357.     -- unlike tran, all merge publications are updateable, so just return all
  16358.     set @cmd = 'select name, pubid, publisher, publisher_db from ' + @dbname + '.dbo.sysmergepublications order by name'
  16359.     exec( @cmd )
  16360.  
  16361.      return (0)
  16362.  
  16363. end
  16364. go
  16365. exec dbo.sp_MS_marksystemobject sp_MShelpmergeconflictpublications
  16366. go
  16367. grant execute on dbo.sp_MShelpmergeconflictpublications to public
  16368. go
  16369.  
  16370.  
  16371. create procedure sp_MSclearcolumnbit
  16372. @pubid            uniqueidentifier,
  16373. @artid            uniqueidentifier,
  16374. @column_name    sysname
  16375. as 
  16376.  
  16377. declare @tablename        sysname
  16378. declare @colid            int
  16379. declare @in_use            bit
  16380. declare @objid            int
  16381. declare @columns         varbinary(128)
  16382. declare @local_repid    uniqueidentifier
  16383. declare @publish        int
  16384. set nocount on 
  16385.  
  16386. set @publish        = 0x4000
  16387. set @in_use=0
  16388. set @local_repid    = NULL
  16389.  
  16390. select @tablename = object_name(objid), @objid=objid from sysmergearticles where artid=@artid and pubid=@pubid
  16391.  
  16392. select @colid=colid from syscolumns where id=@objid and name=@column_name
  16393.  
  16394. select top 1 @local_repid=pubid from sysmergearticles where artid=@artid and pubid<>@pubid order by pubid ASC
  16395. if @local_repid is NULL
  16396. begin
  16397.     update syscolumns set colstat = colstat & ~@publish where id=@objid and colid=@colid
  16398.     if @@ERROR<>0
  16399.         return (1)
  16400.     return (0)
  16401. end
  16402. while @local_repid is not NULL and @in_use=0
  16403. begin
  16404.     select @columns = columns from sysmergearticles where pubid=@local_repid and artid=@artid
  16405.     exec @in_use = sp_MStestbit @bm=@columns, @coltotest=@colid
  16406.     set @local_repid    = NULL
  16407.     select top 1 @local_repid=pubid from sysmergearticles where artid=@artid and pubid>@local_repid order by pubid ASC
  16408. end
  16409. if @in_use=0
  16410. begin
  16411.     update syscolumns set colstat = colstat & ~@publish where id=@objid and colid=@colid
  16412.     if @@ERROR<>0
  16413.         return (1)
  16414. end
  16415. return (0)
  16416. go
  16417. exec dbo.sp_MS_marksystemobject sp_MSclearcolumnbit 
  16418. go
  16419.  
  16420.  
  16421.  
  16422. /*
  16423. ** Name :       sp_helpmergearticleconflicts
  16424. ** Description: This sp returns the articles in the publication that have conflicts.
  16425. **              Optionally if the publication is not specified, all articles in the 
  16426. **              database that have conflicts is returned.
  16427. ** Parameters:  Publication Name( default NULL)
  16428. ** Output Result Set has the following columns
  16429. **              publication, article, source_object, conflict_table, guidcolname
  16430. */
  16431. raiserror('Creating procedure sp_helpmergearticleconflicts', 0,1)
  16432. GO
  16433. CREATE PROCEDURE sp_helpmergearticleconflicts(
  16434.     @publication    sysname = '%',
  16435.     @publisher        sysname = NULL,
  16436.     @publisher_db    sysname = NULL
  16437.     )
  16438. as
  16439.     set nocount on
  16440.     declare @pubid          uniqueidentifier
  16441.     declare @cmd            nvarchar(4000)
  16442.  
  16443.     declare @retcode        int
  16444.     declare @nickname        int
  16445.     declare @retcode2         int
  16446.     declare @name            sysname
  16447.     declare @source_owner    sysname
  16448.     declare @source_object    sysname
  16449.     declare @conflict_table    sysname
  16450.     declare @guidcolname        sysname
  16451.     declare @centralized_conflicts int
  16452.     declare @objid            int
  16453.     declare @command        nvarchar(200)
  16454.  
  16455.     if @publisher IS NULL
  16456.         select @publisher = @@SERVERNAME
  16457.         
  16458.     if @publisher_db IS NULL
  16459.         select @publisher_db = db_name()
  16460.     /*
  16461.     ** Security Check
  16462.     */
  16463.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  16464.     IF @@ERROR <> 0 or @retcode <> 0
  16465.         return (1)
  16466.         
  16467.     if @publication <> '%'
  16468.         begin
  16469.             /*
  16470.             ** Parameter Check:  @publication.
  16471.             ** Make sure that the publication exists.
  16472.             */
  16473.             select @pubid = pubid from sysmergepublications 
  16474.                 where name = @publication and 
  16475.                     LOWER(publisher) = LOWER(@publisher) and
  16476.                     publisher_db = @publisher_db
  16477.             if @pubid IS NULL
  16478.                 BEGIN
  16479.                     RAISERROR (20026, 16, -1, @publication)
  16480.                     RETURN (1)
  16481.                 END
  16482.         end
  16483.  
  16484.     create table #temp_conflict(article                 sysname collate database_default,
  16485.                                 source_owner            sysname collate database_default,
  16486.                                 source_object            sysname collate database_default,
  16487.                                 conflict_table            sysname collate database_default,
  16488.                                 guidcolname                sysname collate database_default,
  16489.                                 centralized_conflicts    int)     
  16490.  
  16491.     declare #cur_conflict cursor local for 
  16492.         select name, objid, conflict_table, pubid, nickname from sysmergearticles 
  16493.             where conflict_table is not NULL and pubid in (select pubid from sysmergepublications where name like @publication)
  16494.                 for read only
  16495.     open #cur_conflict
  16496.     fetch #cur_conflict into @name, @objid, @conflict_table, @pubid, @nickname
  16497.     while (@@fetch_status <> -1)
  16498.     begin
  16499.         select @source_owner = user_name(uid) from sysobjects where id = @objid
  16500.         select @source_object = object_name (@objid)
  16501.         select @guidcolname = name from syscolumns where id = @objid and ColumnProperty(@objid, name, 'IsRowGuidCol') = 1
  16502.         select @centralized_conflicts = centralized_conflicts from sysmergepublications where pubid = @pubid
  16503.  
  16504.         select @command = 'if exists (select * from ' + QUOTENAME(@conflict_table) + ') select @retcode2 = 1
  16505.                                 else select @retcode2 = 0'
  16506.         EXEC @retcode = dbo.sp_executesql @command, N'@retcode2 int output', @retcode2 output
  16507.         if @retcode <>0
  16508.                 return (1)
  16509.         if @retcode2 = 1 
  16510.         begin
  16511.             insert into #temp_conflict 
  16512.                 values (@name, @source_owner, @source_object, @conflict_table, @guidcolname, @centralized_conflicts)
  16513.         end
  16514.         if EXISTS (select * from MSmerge_delete_conflicts where tablenick = @nickname)
  16515.         begin
  16516.             insert into #temp_conflict
  16517.                 values (@name, @source_owner, @source_object, 'MSmerge_delete_conflicts', @guidcolname, @centralized_conflicts)
  16518.         end
  16519.         fetch #cur_conflict into @name, @objid, @conflict_table, @pubid, @nickname
  16520.     end
  16521.  
  16522.     select * from #temp_conflict order by article
  16523.  
  16524.     drop table #temp_conflict
  16525.     close #cur_conflict
  16526.     deallocate #cur_conflict
  16527. return(0)       
  16528. go
  16529. exec dbo.sp_MS_marksystemobject sp_helpmergearticleconflicts 
  16530. go
  16531. grant execute on dbo.sp_helpmergearticleconflicts to public
  16532. go
  16533. /*
  16534. ** Name :       sp_helpmergeconflictrows
  16535. ** Description: This sp returns the rows in the conflict_table specified. 
  16536. **              Optionally if the publication is specified, all conflicts qualified by the
  16537. **              publication are returned. For instance if the Conflict_Customers table 
  16538. **              has conflict rows for the 'WA' and the 'CA' publication, passing in 
  16539. **              a publication name say 'CA' retrieves conflicts pertaining to the 
  16540. **              'CA' publication.
  16541. ** Parameters:  1. Publication Name( default NULL)
  16542. **              2. Conflict Table Name
  16543. ** Output Result Set has the same structure as the Conflict_<table> i.e the base
  16544. ** table structure with the following additional columns:
  16545. **  ----------------------------------------------------------------------------------
  16546. **      Name                Datatype            Description
  16547. **  ----------------------------------------------------------------------------------
  16548. **  a. origin_datasource    (varchar(255))      Indicates the origin of the conflict                                                         
  16549. **  b. conflict_type        (int)               Code indicating type of conflict
  16550. **                                              UpdateConflict      = 1
  16551. **                                              UploadError         = 2
  16552. **                                              DownloadError       = 3
  16553. **                                              UpdateDeleteConflict= 4
  16554. **                                              ColumnUpdateConflict= 5
  16555. **  c. reason_code          (int)               Error code that may be context sensitive 
  16556. **  d. reason_text          (varchar(720))      Error description that may be context sensitive                                                          
  16557. **  e. pubid                (uniqueidentifier)  Publication identifier
  16558. */
  16559. raiserror('Creating procedure sp_helpmergeconflictrows', 0,1)
  16560. GO
  16561. CREATE PROCEDURE sp_helpmergeconflictrows(
  16562.     @publication    sysname = '%',
  16563.     @conflict_table sysname,
  16564.     @publisher        sysname = NULL,
  16565.     @publisher_db    sysname = NULL
  16566.     
  16567.     )
  16568. as 
  16569.     set nocount on
  16570.     declare @pubid          uniqueidentifier
  16571.     declare @cmd            nvarchar(4000)  
  16572.     declare @pubidstr       nvarchar(38)
  16573.     declare @retcode        int
  16574.     /*
  16575.     ** Security Check
  16576.     */
  16577.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  16578.     IF @@ERROR <> 0 or @retcode <> 0
  16579.         return (1)
  16580.         
  16581.     if @publisher IS NULL
  16582.         select @publisher = @@SERVERNAME
  16583.         
  16584.     if @publisher_db IS NULL
  16585.         select @publisher_db = db_name()
  16586.     select @cmd = 'select * from ' 
  16587.     select @cmd = @cmd + QUOTENAME(@conflict_table)
  16588.     if @publication <> '%'
  16589.     begin
  16590.         /*
  16591.         ** Parameter Check:  @publication.
  16592.         ** Make sure that the publication exists.
  16593.         */
  16594.         select @pubid = pubid from sysmergepublications 
  16595.             where name = @publication and 
  16596.                 LOWER(publisher) = LOWER(@publisher) and
  16597.                 publisher_db = @publisher_db
  16598.         if @pubid IS NULL
  16599.         BEGIN
  16600.             RAISERROR (20026, 16, -1, @publication)
  16601.             RETURN (1)
  16602.         END
  16603.  
  16604.         set @pubidstr = '''' + convert(nchar(36), @pubid) + '''' 
  16605.         select @cmd = @cmd + ' where pubid = ' + @pubidstr
  16606.     end
  16607.  
  16608.     -- Security check
  16609.     if 1 <> is_member('db_owner') and 
  16610.        (1 <> is_member('replmonitor') or is_member('replmonitor') is null)
  16611.     begin
  16612.         exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @publication = @publication, @pubid = @pubid
  16613.         if @retcode<>0 or @@ERROR<>0
  16614.         begin    
  16615.             RAISERROR (15247, 11, -1)
  16616.             return (1)
  16617.         end
  16618.     end
  16619.  
  16620.     exec (@cmd)
  16621.     if (@@error <> 0)
  16622.         RETURN (1)
  16623.     
  16624.     return 0
  16625. go
  16626.  
  16627. exec dbo.sp_MS_marksystemobject sp_helpmergeconflictrows 
  16628. go
  16629. grant execute on dbo.sp_helpmergeconflictrows to public
  16630. go
  16631.  
  16632. /*
  16633. ** Name :       sp_helpmergedeleteconflictrows
  16634. ** Description: This sp returns the rows in the MSmerge_delete_conflicts specified. 
  16635. **              Optionally if the publication is specified, all conflicts qualified by the
  16636. **              publication are returned. For instance if the MSmerge_delete_conflicts table 
  16637. **              has conflict rows for the 'WA' and the 'CA' publication, passing in 
  16638. **              a publication name say 'CA' retrieves conflicts pertaining to the 
  16639. **              'CA' publication only.
  16640. ** Parameters:  1. Publication Name( default NULL)
  16641. **              2. Source Object Name
  16642. ** Output Result Set has the following structure 
  16643. **  ----------------------------------------------------------------------------------
  16644. **      Name                Datatype                Description
  16645. **  ----------------------------------------------------------------------------------
  16646. **  a. source_object        (nvarchar(386))     Indicates the source object for the delete conflict                                                         
  16647. **  b. rowguid              (uniqueidentifier)  Row identifier for the delete conflict
  16648. **  c. origin_datasource    (varchar(255))      Indicates the origin of the conflict                                                         
  16649. **  d. conflict_type        (int)               Code indicating type of conflict
  16650. **                                              UpdateConflict      = 1
  16651. **                                              UploadError         = 2
  16652. **                                              DownloadError       = 3
  16653. **                                              UpdateDeleteConflict= 4
  16654. **                                              ColumnUpdateConflict= 5
  16655. **  e. reason_code          (int)               Error code that may be context sensitive 
  16656. **  f. reason_text          (varchar(720))      Error description that may be context sensitive                                                          
  16657. **  g. pubid                (uniqueidentifier)  Publication identifier
  16658. */
  16659. raiserror('Creating procedure sp_helpmergedeleteconflictrows', 0,1)
  16660. GO
  16661.  
  16662. CREATE PROCEDURE sp_helpmergedeleteconflictrows(
  16663.     @publication    sysname = '%',
  16664.     @source_object  nvarchar(386) = NULL,
  16665.     @publisher        sysname = NULL,
  16666.     @publisher_db    sysname = NULL
  16667.     )
  16668. as
  16669.     declare @pubid          uniqueidentifier
  16670.     declare @cmd            nvarchar(4000)  
  16671.     declare @pubidstr       nvarchar(38)
  16672.     declare @retcode        int
  16673.     /*
  16674.     ** Security Check
  16675.     */
  16676.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  16677.     IF @@ERROR <> 0 or @retcode <> 0
  16678.         return (1)
  16679.     if @publisher IS NULL
  16680.         select @publisher = @@SERVERNAME
  16681.         
  16682.     if @publisher_db IS NULL
  16683.         select @publisher_db = db_name()
  16684.     select @cmd = 'select distinct source_object =  user_name(sysobjects.uid) + '
  16685.     select @cmd = @cmd + '''.'''
  16686.     select @cmd = @cmd + ' + sysobjects.name, MSmerge_delete_conflicts.rowguid, MSmerge_delete_conflicts.conflict_type, '
  16687.     select @cmd = @cmd + ' MSmerge_delete_conflicts.reason_code, MSmerge_delete_conflicts.reason_text, '
  16688.     select @cmd = @cmd + ' MSmerge_delete_conflicts.origin_datasource, MSmerge_delete_conflicts.pubid, MSmerge_delete_conflicts.create_time from MSmerge_delete_conflicts, sysmergearticles, sysobjects'  
  16689.     select @cmd = @cmd + ' where sysmergearticles.nickname = MSmerge_delete_conflicts.tablenick and sysobjects.id = sysmergearticles.objid '
  16690.     if @publication <> '%'
  16691.         begin
  16692.             /*
  16693.             ** Parameter Check:  @publication.
  16694.             ** Make sure that the publication exists.
  16695.             */
  16696.             select @pubid = pubid from sysmergepublications 
  16697.                 where name = @publication and 
  16698.                     LOWER(publisher) = LOWER(@publisher) and
  16699.                     publisher_db = @publisher_db
  16700.             if @pubid IS NULL
  16701.                 BEGIN
  16702.                     RAISERROR (20026, 16, -1, @publication)
  16703.                     RETURN (1)
  16704.                 END
  16705.             set @pubidstr = '''' + convert(nchar(36), @pubid) + '''' 
  16706.             select @cmd = @cmd + ' and MSmerge_delete_conflicts.pubid = ' + @pubidstr
  16707.         end
  16708.  
  16709.     if @source_object IS NOT NULL
  16710.         begin
  16711.             declare @object         sysname  
  16712.             declare @owner          sysname  
  16713.             declare @tablenick      int
  16714.             declare @tablenickstr   nvarchar(11)
  16715.             
  16716.             select @object = PARSENAME(@source_object, 1)
  16717.             select @owner = PARSENAME(@source_object, 2)
  16718.             execute dbo.sp_MStablenickname @owner, @object, @tablenick output
  16719.             if @tablenick IS NULL
  16720.                 BEGIN
  16721.                     raiserror (20003, 11, -1, @object)
  16722.                     RETURN (1)
  16723.                 END
  16724.             set @tablenickstr = convert(nchar, @tablenick)
  16725.             select @cmd = @cmd + ' and MSmerge_delete_conflicts.tablenick = '
  16726.             select @cmd = @cmd + @tablenickstr
  16727.         end
  16728.  
  16729.     exec (@cmd)
  16730.     if (@@error <> 0)
  16731.         RETURN (1)
  16732.     
  16733.     return 0
  16734. go
  16735.  
  16736. exec dbo.sp_MS_marksystemobject sp_helpmergedeleteconflictrows 
  16737. go
  16738. grant exec on dbo.sp_helpmergedeleteconflictrows to public
  16739. go
  16740.  
  16741. /*
  16742. ** Name :       sp_deletemergeconflictrow
  16743. ** Description: This sp deletes the row matching rowguid and origin_datasource
  16744. **              If now rows are left in conflict_table
  16745. **                  --Set the conflict_table property of the article(s) to NULL
  16746. **                  --Drop the conflict table (optionally)
  16747. **              If the conflict_table is specified as NULL, the conflict is assumed
  16748. **              to be a delete conflict and the row matching rowguid and origin_datasource
  16749. **              and source_object is deleted from the MSmerge_delete_conflicts table. The
  16750. **              MSmerge_delete_conflicts table is a system table and is not deleted 
  16751. **              from the database even if it is empty.
  16752. ** Parameters:  
  16753. **  ----------------------------------------------------------------------------------
  16754. **      Name                Datatype                Description
  16755. **  ----------------------------------------------------------------------------------
  16756. **  a. conflict_table       (sysname)           Indicates the conflict table name. If
  16757.                                                 '%' then delete from MSmerge_delete_conflicts
  16758. **  b. source_object        (nvarchar(386))     Source table 
  16759. **  c. rowguid              (uniqueidentifier)  Row identifier for the delete conflict
  16760. **  d. origin_datasource    (varchar(255))      Indicates the origin of the conflict                                                         
  16761. **  e. drop_table_if_empty  (varchar(10))       Flag indicating if the Conflict_<table>
  16762. **                                              is to be dropped if is empty
  16763. */
  16764. raiserror('Creating procedure sp_deletemergeconflictrow', 0,1)
  16765. GO
  16766.  
  16767. CREATE PROCEDURE sp_deletemergeconflictrow(
  16768.     @conflict_table         sysname = '%',
  16769.     @source_object          nvarchar(386) = NULL,
  16770.     @rowguid                uniqueidentifier,
  16771.     @origin_datasource      varchar(255),
  16772.     @drop_table_if_empty    varchar(10) = 'false')
  16773. as
  16774.     declare @retcode        smallint
  16775.     declare @cmd            nvarchar(4000)  
  16776.     declare @rowguidstr     nvarchar(40)
  16777.     declare @object         sysname  
  16778.     declare @owner          sysname  
  16779.     declare @tablenick      int
  16780.     declare @tablenickstr   nvarchar(11)
  16781.  
  16782.     /*
  16783.     ** Security Check
  16784.     */
  16785.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  16786.     IF @@ERROR <> 0 or @retcode <> 0
  16787.         return (1)
  16788.         
  16789.     set @rowguidstr = convert(nchar(36), @rowguid)
  16790.  
  16791.     /* Delete conflict from Conflict_<Table> */
  16792.     if @conflict_table <> '%'
  16793.         begin
  16794.             select @cmd = 'delete from '
  16795.             select @cmd = @cmd + quotename(@conflict_table) 
  16796.             select @cmd = @cmd + ' where origin_datasource = '''
  16797.             select @cmd = @cmd + @origin_datasource 
  16798.             select @cmd = @cmd + ''' and rowguidcol = '''
  16799.             select @cmd = @cmd + @rowguidstr
  16800.             select @cmd = @cmd + ''''
  16801.             exec (@cmd)
  16802.             if @@ERROR<>0 return (1)
  16803.  
  16804.             if LOWER(@drop_table_if_empty collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  16805.                 begin
  16806.                     select @cmd = 'if not exists (select 1 from ' 
  16807.                     select @cmd = @cmd + quotename(@conflict_table) 
  16808.                     select @cmd = @cmd + ')'
  16809.                     select @cmd = @cmd + ' update sysmergearticles set ins_conflict_proc = NULL, conflict_table = NULL where conflict_table = ' + quotename(@conflict_table)
  16810.                     exec (@cmd)
  16811.                     if @@ERROR<>0 
  16812.                         return (1)
  16813.                         
  16814.                     select @cmd = 'if not exists (select 1 from ' 
  16815.                     select @cmd = @cmd + quotename(@conflict_table)
  16816.                     select @cmd = @cmd + ')'
  16817.                     select @cmd = @cmd + ' drop table '
  16818.                     select @cmd = @cmd + quotename(@conflict_table)
  16819.                     select @cmd = @cmd + ''
  16820.                     exec (@cmd)
  16821.                     if @@ERROR<>0 return (1)
  16822.                 end
  16823.         end
  16824.     /* Delete conflict from MSmerge_delete_conflicts */
  16825.     else
  16826.         begin
  16827.             if @source_object is NULL
  16828.                 begin
  16829.                     raiserror(14043, 16, -1, '@source_object')
  16830.                     return (1)
  16831.                 end
  16832.             select @object = PARSENAME(@source_object, 1)
  16833.             select @owner = PARSENAME(@source_object, 2)
  16834.             execute @retcode=sp_MStablenickname @owner, @object, @tablenick output
  16835.         
  16836.             if @tablenick IS NULL or @@ERROR<>0 or @retcode<>0
  16837.                 BEGIN
  16838.                     raiserror (20003, 11, -1, @object)
  16839.                     RETURN (1)
  16840.                 END
  16841.  
  16842.             set @tablenickstr = convert(nchar, @tablenick)
  16843.  
  16844.             
  16845.             select @cmd = 'delete from MSmerge_delete_conflicts'
  16846.             select @cmd = @cmd + ' where origin_datasource = '''
  16847.             select @cmd = @cmd + @origin_datasource 
  16848.             select @cmd = @cmd + ''' and tablenick = '
  16849.             select @cmd = @cmd + @tablenickstr
  16850.             select @cmd = @cmd + ' and rowguid = '''
  16851.             select @cmd = @cmd + @rowguidstr
  16852.             select @cmd = @cmd + ''''
  16853.             exec (@cmd)
  16854.             if @@ERROR<>0 return (1)
  16855.  
  16856.         end
  16857.  
  16858. go
  16859.  
  16860. exec dbo.sp_MS_marksystemobject sp_deletemergeconflictrow 
  16861. go
  16862. grant exec on dbo.sp_deletemergeconflictrow to public
  16863. go
  16864.  
  16865. /*
  16866. ** Name :       sp_getmergedeletetype
  16867. ** Description: This sp returns the type of delete
  16868. ** Parameters:  
  16869. **  ----------------------------------------------------------------------------------
  16870. **      Name                Datatype                Description
  16871. **  ----------------------------------------------------------------------------------
  16872. **  a. source_object        (nvarchar(386))     Indicates the source object
  16873. **  b. rowguid              (uniqueidentifier)  Row identifier for the delete conflict
  16874. **  c. delete_type(OUTPUT)  (int)               Code indicating delete type
  16875. **                                              User Delete     -   1
  16876. **                                              Partial Delete  -   5                                                       
  16877. **                                              System Delete   -   6                                                       
  16878. */
  16879. raiserror('Creating procedure sp_getmergedeletetype', 0,1)
  16880. GO
  16881.  
  16882. CREATE PROCEDURE sp_getmergedeletetype(
  16883.     @source_object  nvarchar (386),
  16884.     @rowguid        uniqueidentifier,
  16885.     @delete_type    int OUTPUT
  16886. )
  16887. as
  16888.     declare @object         sysname  
  16889.     declare @owner          sysname  
  16890.     declare @tablenick      int
  16891.     declare @retcode        int
  16892.     /*
  16893.     ** Security Check
  16894.     */
  16895.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  16896.     IF @@ERROR <> 0 or @retcode <> 0
  16897.         return (1)
  16898.         
  16899.     select @object = PARSENAME(@source_object, 1)
  16900.     select @owner = PARSENAME(@source_object, 2)
  16901.     execute dbo.sp_MStablenickname @owner, @object, @tablenick output
  16902.     if @tablenick IS NULL OR @@ERROR<>0
  16903.         BEGIN
  16904.             raiserror (20003, 11, -1, @object)
  16905.             RETURN (1)
  16906.         END
  16907.  
  16908.     if @rowguid IS NULL 
  16909.         begin
  16910.             raiserror (14027, 11, -1, '@rowguid')
  16911.             return (1)
  16912.         end
  16913.         
  16914.     select @delete_type = type from MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick
  16915. go
  16916.  
  16917. exec dbo.sp_MS_marksystemobject sp_getmergedeletetype 
  16918. go
  16919. grant exec on dbo.sp_getmergedeletetype to public
  16920. go
  16921.  
  16922. /*
  16923. ** Name :       sp_mergedummyupdate
  16924. ** Description: This sp does a dummy updates on the given row so that it will be
  16925. **              resent during the next merge.
  16926. * Parameters:   
  16927. **  ----------------------------------------------------------------------------------
  16928. **      Name                Datatype                Description
  16929. **  ----------------------------------------------------------------------------------
  16930. **  a. source_object        (nvarchar(386))     Indicates the source object
  16931. **  b. rowguid              (uniqueidentifier)  Row identifier for the delete conflict
  16932. */
  16933. raiserror('Creating procedure sp_mergedummyupdate', 0,1)
  16934. GO
  16935.  
  16936. CREATE PROCEDURE sp_mergedummyupdate(
  16937.     @source_object  nvarchar (386),
  16938.     @rowguid        uniqueidentifier
  16939. )
  16940. as
  16941.     -- Security check
  16942.     if 1 <> is_member('db_owner')
  16943.     begin    
  16944.         RAISERROR (15247, 11, -1)
  16945.         return (1)
  16946.     end
  16947.     
  16948.     declare @object         sysname  
  16949.     declare @owner          sysname  
  16950.     declare @tablenick      int
  16951.     declare @tablenickstr   nvarchar(11)
  16952.  
  16953.     select @object = PARSENAME(@source_object, 1)
  16954.     select @owner = PARSENAME(@source_object, 2)
  16955.     execute dbo.sp_MStablenickname @owner, @object, @tablenick output
  16956.     if @tablenick IS NULL or @@ERROR<>0
  16957.         BEGIN
  16958.             raiserror (20003, 11, -1, @object)
  16959.             RETURN (1)
  16960.         END
  16961.     set @tablenickstr = convert(nchar, @tablenick)
  16962.  
  16963.     declare @rowguidstr nvarchar(40)
  16964.     if @rowguid IS NULL 
  16965.         begin
  16966.             raiserror (14043, 11, -1, '@rowguid')
  16967.             return (1)
  16968.         end
  16969.     set @rowguidstr = convert(nchar(36), @rowguid)
  16970.     if @@error<>0 return 1
  16971.  
  16972.     declare @quoted_source_object nvarchar(500)
  16973.     if @owner is null
  16974.         set @quoted_source_object= quotename(@object)
  16975.     else
  16976.         set @quoted_source_object= quotename(@owner) + '.' + quotename(@object)
  16977.  
  16978.     /* 
  16979.     ** If the row does not exist in the base table, call sp_MSdummyupdate with metadata_type = 1 (tombstone)
  16980.     */
  16981.     exec ('if not exists (select 1 from ' + @quoted_source_object + ' where rowguidcol = ''' +
  16982.         @rowguidstr + ''' ) exec dbo.sp_MSdummyupdate ''' + @rowguidstr + ''',' + @tablenickstr + ', 1')
  16983.  
  16984.     /* 
  16985.     ** If the row exists in the base table and MSmerge_contents , call sp_MSdummyupdate with metadata_type = 2 (contents)
  16986.     */
  16987.     exec ('if exists (select 1 from ' + @quoted_source_object + ' where rowguidcol = ''' +
  16988.         @rowguidstr + ''' ) and exists (select rowguid from MSmerge_contents where rowguid = ''' +
  16989.         @rowguidstr + ''' ) exec dbo.sp_MSdummyupdate ''' + @rowguidstr + ''',' + @tablenickstr + ', 2')
  16990.  
  16991.     /* 
  16992.     ** If the row exists in the base table, but not in MSmerge_contents , call sp_MSdummyupdate with metadata_type = 3 (contents_deferred)
  16993.     */
  16994.     exec ('if exists (select 1 from ' + @quoted_source_object + ' where rowguidcol = ''' +
  16995.         @rowguidstr + ''' ) and not exists (select rowguid from MSmerge_contents where rowguid = ''' +
  16996.         @rowguidstr + ''' ) exec dbo.sp_MSdummyupdate ''' + @rowguidstr + ''',' + @tablenickstr + ', 3')
  16997.  
  16998.  
  16999. go
  17000. exec dbo.sp_MS_marksystemobject sp_mergedummyupdate 
  17001. go
  17002. grant exec on dbo.sp_mergedummyupdate to public
  17003. go
  17004.  
  17005. raiserror('Creating procedure sp_addtabletocontents', 0,1)
  17006. GO
  17007.  
  17008. create procedure sp_addtabletocontents 
  17009.     (@table_name sysname,
  17010.      @owner_name sysname = NULL)
  17011. AS
  17012.  
  17013.     declare @qualified_table_name nvarchar(270)
  17014.     declare @tablenick int
  17015.     declare @tablenickstr nvarchar(12)
  17016.     declare @repl_nick int
  17017.     declare @lineage varbinary(249)
  17018.     declare @colv varbinary(2000)
  17019.     declare @coltrack int
  17020.     declare @objid int
  17021.     declare @maxcolid int
  17022.     declare @retcode int
  17023.     declare @gen int
  17024.  
  17025.     /*
  17026.     ** Security Check
  17027.     */
  17028.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  17029.     IF @@ERROR <> 0 or @retcode <> 0
  17030.         return (1)
  17031.     
  17032.     set nocount on
  17033.     create table #temp_cont(rowguid uniqueidentifier)
  17034.     execute @retcode = dbo.sp_MSgetreplnick @nickname = @repl_nick output
  17035.     if (@@error <> 0) or @retcode <> 0 or @repl_nick IS NULL 
  17036.         begin
  17037.         RAISERROR (14055, 11, -1)
  17038.         RETURN(1)
  17039.         end                 
  17040.  
  17041.     if @owner_name is NULL
  17042.         begin
  17043.         select @owner_name = user_name(uid) from sysobjects where name = @table_name
  17044.         end
  17045.     set @qualified_table_name = QUOTENAME(@owner_name) + '.' + QUOTENAME(@table_name)
  17046.     
  17047.     set @objid = object_id(@qualified_table_name)
  17048.     if @objid is NULL return (1)
  17049.     select @gen = max(gen_cur), @tablenick = max(nickname), @coltrack = max(column_tracking) from sysmergearticles where objid = @objid
  17050.     if @gen is null
  17051.         set @gen = 0
  17052.     select @maxcolid = max(colid) from syscolumns where id = @objid
  17053.  
  17054.     if @coltrack = 1
  17055.         set @colv = { fn INITCOLVS(@maxcolid, @repl_nick) }
  17056.     else
  17057.         set @colv = NULL
  17058.     set @lineage = { fn UPDATELINEAGE(0x0, @repl_nick, 1) }
  17059.  
  17060.     set @tablenickstr = convert(nchar, @tablenick)
  17061.  
  17062.     exec ('insert into #temp_cont(rowguid) select RowGuidCol from ' + @qualified_table_name + ' where
  17063.             RowGuidCol not in (select rowguid from MSmerge_contents where tablenick = 
  17064.             ' + @tablenickstr + ')')
  17065.  
  17066.     insert into MSmerge_contents (tablenick, rowguid, generation, joinchangegen, lineage, colv1)
  17067.         select @tablenick, rowguid, @gen, @gen, @lineage, @colv from #temp_cont
  17068.  
  17069.     drop table #temp_cont
  17070. GO
  17071. exec dbo.sp_MS_marksystemobject sp_addtabletocontents 
  17072. go
  17073. grant exec on dbo.sp_addtabletocontents to public
  17074. go
  17075.  
  17076.  
  17077.  
  17078.  
  17079.  
  17080. raiserror('Creating procedure sp_MSaddpubtocontents', 0,1)
  17081. GO
  17082.  
  17083. create procedure sp_MSaddpubtocontents 
  17084.     (@publication   sysname)
  17085. AS
  17086.     declare     @pubid  uniqueidentifier
  17087.     declare     @tablenick int
  17088.     declare     @retcode int
  17089.     declare     @objid int
  17090.     declare     @owner sysname
  17091.     declare        @table sysname
  17092.     
  17093.     set nocount on
  17094.     /*
  17095.     ** Security Check
  17096.     */
  17097.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  17098.     IF @@ERROR <> 0 or @retcode <> 0
  17099.         return (1)
  17100.  
  17101.     select @pubid = pubid from sysmergepublications 
  17102.         where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
  17103.     if @pubid is NULL
  17104.         begin
  17105.             raiserror (20026, 11, -1, @publication)
  17106.             return (1)
  17107.         end
  17108.     
  17109.     select @tablenick = min(nickname) from sysmergearticles where pubid = @pubid
  17110.  
  17111.     while @tablenick is not null
  17112.         begin
  17113.         select @objid = objid from sysmergearticles where pubid = @pubid and
  17114.             nickname = @tablenick
  17115.         select @owner = user_name(uid) from sysobjects where id = @objid
  17116.         set @table = OBJECT_NAME(@objid)
  17117.         exec @retcode = dbo.sp_addtabletocontents @table, @owner
  17118.         
  17119.         IF @@ERROR <> 0 or @retcode <> 0
  17120.             return (1)
  17121.  
  17122.         select @tablenick = min(nickname) from sysmergearticles where pubid = @pubid and
  17123.                 nickname > @tablenick
  17124.         end
  17125. GO
  17126. exec dbo.sp_MS_marksystemobject sp_MSaddpubtocontents 
  17127. go
  17128. grant exec on dbo.sp_MSaddpubtocontents to public
  17129. go
  17130.  
  17131. raiserror(15339,-1,-1,'sp_MSget_subtypedatasrc')
  17132. GO
  17133. CREATE PROCEDURE sp_MSget_subtypedatasrc
  17134. @subscriber                sysname,
  17135. @distributor            sysname,
  17136. @distribdb                sysname,
  17137. @datasrctype            int OUTPUT,
  17138. @datasrc                sysname OUTPUT
  17139. AS
  17140.     SET NOCOUNT ON
  17141.  
  17142.     DECLARE @provider_name        sysname
  17143.     DECLARE @jet_subscriber     tinyint
  17144.     DECLARE @oledb_subscriber   tinyint
  17145.     DECLARE @oracle_subscriber  tinyint
  17146.     DECLARE @db2universal_subscriber tinyint
  17147.     DECLARE @distproc           nvarchar(300)
  17148.     DECLARE @cmd                 nvarchar(512)
  17149.     declare @retcode            int
  17150.     
  17151.     set @jet_subscriber = 2   
  17152.     set @oledb_subscriber = 3 
  17153.     set @oracle_subscriber = 5 
  17154.     set @db2universal_subscriber = 6
  17155.     
  17156.     create table #subtype
  17157.     (
  17158.         type tinyint not null,   
  17159.     )
  17160.  
  17161.     create table #server_info 
  17162.     (
  17163.         providername nvarchar(256) collate database_default null,
  17164.         datasource nvarchar(3750) collate database_default null,            -- this column is nvarchar(4000) in sysservers, but we want to avoid info msg
  17165.                                                                             -- from create table when row size > 8060 bytes.
  17166.     )
  17167.  
  17168.     SELECT @distproc = RTRIM(@distributor) + '.' +
  17169.         RTRIM(@distribdb) + '.dbo.sp_executesql'
  17170.  
  17171.     select @cmd = 'select type from MSsubscriber_info where UPPER(subscriber) = UPPER(@subscriber) and UPPER(publisher) = @servername'
  17172.     insert into #subtype exec @retcode= @distproc @cmd, N'@subscriber sysname, @servername sysname', @subscriber=@subscriber, @servername=@@servername
  17173.     if (@@error <> 0 or @@rowcount <> 1 or @retcode <> 0)
  17174.     begin
  17175.         drop table #subtype
  17176.         drop table #server_info
  17177.         raiserror(14085, 16, -1)
  17178.         return 1
  17179.     end
  17180.     
  17181.     select @datasrctype = type from #subtype
  17182.     
  17183.     SELECT @cmd = 'select providername, datasource from master..sysservers where UPPER(srvname) = UPPER(@subscriber)'
  17184.     
  17185.     insert into #server_info exec @retcode= @distproc @cmd, N'@subscriber sysname', @subscriber=@subscriber
  17186.     if (@@error <> 0 or @@rowcount <> 1 or @retcode <> 0)
  17187.     begin
  17188.         drop table #subtype
  17189.         drop table #server_info
  17190.         raiserror(14085, 16, -1)
  17191.         return 1
  17192.     end
  17193.     
  17194.     select @datasrc = datasource, @provider_name =  providername from #server_info
  17195.     
  17196.     /*
  17197.     ** Jet and Oracle subscribers are actually added to MSsubscriber_info as OLE DB subscribers,
  17198.     ** since they can be used in transactional replication also.
  17199.     ** Map the type to Jet or Oracle based on OLE DB provider name.
  17200.     */
  17201.     
  17202.     if (@datasrctype = @oledb_subscriber) 
  17203.     BEGIN
  17204.         if (upper(@provider_name collate SQL_Latin1_General_CP1_CS_AS) = 'MICROSOFT.JET.OLEDB.4.0')
  17205.             select @datasrctype = @jet_subscriber
  17206.         else if (upper(@provider_name collate SQL_Latin1_General_CP1_CS_AS) = 'MSDAORA')
  17207.             select @datasrctype = @oracle_subscriber
  17208.         else if (upper(@provider_name collate SQL_Latin1_General_CP1_CS_AS) = 'DB2OLEDB')
  17209.             select @datasrctype = @db2universal_subscriber
  17210.     END
  17211.     
  17212.     drop table #subtype
  17213.     drop table #server_info
  17214.  
  17215.     return 0
  17216. GO
  17217. exec dbo.sp_MS_marksystemobject sp_MSget_subtypedatasrc 
  17218. go
  17219.  
  17220.  
  17221. raiserror('Creating procedure sp_addmergealternatepublisher', 0,1)
  17222. GO
  17223. CREATE PROCEDURE sp_addmergealternatepublisher (
  17224.     @publisher                    sysname,                     /* Publisher server */
  17225.     @publisher_db               sysname,                     /* Publisher database */
  17226.     @publication                sysname,                    /* Publication name */
  17227.     @alternate_publisher        sysname,                    /* Alternate publisher */
  17228.     @alternate_publisher_db     sysname,                    /* Alternate publisher_db */
  17229.     @alternate_publication        sysname,                    /* Alternate publication */
  17230.     @alternate_distributor        sysname,                    /* Alternate publisher's Distributor */
  17231.     @friendly_name                nvarchar(255)    = NULL,        /* Friendly Name for the association */
  17232.     @reserved                   nvarchar(20) = NULL            /* Reserved param for internal use only */
  17233.     ) AS
  17234.  
  17235.     SET NOCOUNT ON
  17236.  
  17237.     /*
  17238.     ** Declarations.
  17239.     */
  17240.     declare @retcode                int
  17241.     declare @pubid                    uniqueidentifier
  17242.     declare @subid                    uniqueidentifier
  17243.     declare @alternate_subid        uniqueidentifier
  17244.     declare    @description            nvarchar(255)
  17245.     declare    @allow_synctoalternate    bit
  17246.     declare @at_publisher            bit
  17247.     declare @subscriber_type        smallint
  17248.  
  17249.     set @at_publisher = 1
  17250.      /*
  17251.     ** Security Check
  17252.     */
  17253.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  17254.     IF @@ERROR <> 0 or @retcode <> 0
  17255.         return (1)
  17256.     
  17257.     /*
  17258.     ** Select the subscription's pubid and subid
  17259.     */
  17260.     select @pubid = pubid, @allow_synctoalternate = allow_synctoalternate from sysmergepublications  
  17261.         where name = @publication and publisher_db = @publisher_db and LOWER(publisher) = LOWER(@publisher)
  17262.     if @pubid is NULL
  17263.         begin
  17264.             raiserror (20026, 11, -1, @publication)
  17265.             return (1)
  17266.         end
  17267.  
  17268.     /* If this is an external call, make the AtPublisher and allows syncto alternate  check */
  17269.     EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
  17270.     IF @@ERROR <> 0 or @retcode <>  0
  17271.         set @at_publisher = 0
  17272.         
  17273.     IF LOWER(@reserved collate SQL_Latin1_General_CP1_CS_AS) <> 'internal'
  17274.         begin
  17275.             IF @at_publisher = 0
  17276.                 BEGIN
  17277.                     RAISERROR (21215, 16, -1)
  17278.                     RETURN (1)
  17279.                 END
  17280.             if @allow_synctoalternate = 0
  17281.                 begin
  17282.                     raiserror (21502, 11, -1, @publication)
  17283.                     return (1)
  17284.                 end
  17285.  
  17286.         end
  17287.     select @subid = subid from sysmergesubscriptions  
  17288.         where LOWER(subscriber_server) = LOWER(@publisher) and db_name = @publisher_db and pubid = @pubid
  17289.     /*
  17290.     ** Select the alternate publisher's subid 
  17291.     */
  17292.     select @alternate_subid = subid, @subscriber_type = subscriber_type from sysmergesubscriptions
  17293.         where publication = @alternate_publication
  17294.         and LOWER(subscriber_server) = LOWER(@alternate_publisher) and db_name = @alternate_publisher_db
  17295.     IF @subid is NULL or @alternate_subid IS NULL
  17296.         BEGIN
  17297.             RAISERROR(21216, 11, -1,  @alternate_publisher, @alternate_publisher_db, @alternate_publication)
  17298.             RETURN (1)
  17299.         END
  17300.     IF @subscriber_type  <> 1
  17301.         BEGIN
  17302.             RAISERROR(21216, 11, -1,  @alternate_publisher, @alternate_publisher_db, @alternate_publication)
  17303.             RETURN (1)
  17304.         END
  17305.  
  17306.     IF @friendly_name IS NULL
  17307.         begin
  17308.             select @description = description from sysmergesubscriptions where subid = @alternate_subid
  17309.             if @description IS NULL
  17310.                 begin
  17311.                     select @description = formatmessage(21217, @alternate_publication, @alternate_publisher)
  17312.                 end
  17313.                 
  17314.         end                
  17315.     else
  17316.         select @description = @friendly_name
  17317.  
  17318.  
  17319.     if not exists (select * from MSmerge_altsyncpartners where subid = @subid and alternate_subid = @alternate_subid)
  17320.         begin
  17321.             insert into MSmerge_altsyncpartners(subid, alternate_subid, description)
  17322.                 values(@subid, @alternate_subid, @description)
  17323.             if @@ERROR <> 0
  17324.                 BEGIN
  17325.                     GOTO FAILURE
  17326.                 END
  17327.  
  17328.             update sysmergesubscriptions set distributor = @alternate_distributor where subid = @alternate_subid
  17329.             if @@ERROR <> 0 or @@ROWCOUNT <> 1
  17330.                 BEGIN
  17331.                     GOTO FAILURE
  17332.                 END
  17333.         end                
  17334.     if not exists (select * from MSmerge_altsyncpartners where subid = @alternate_subid and alternate_subid = @subid)
  17335.         begin
  17336.             insert into MSmerge_altsyncpartners(subid, alternate_subid, description)
  17337.                 values(@alternate_subid, @subid, @description)
  17338.             if @@ERROR <> 0
  17339.                 BEGIN
  17340.                     GOTO FAILURE
  17341.                 END
  17342.         end                
  17343.     return (0)
  17344.  
  17345. FAILURE:
  17346.  
  17347.     RAISERROR(21243, 11, -1,  @alternate_publisher, @alternate_publisher_db, @alternate_publication)
  17348.     RETURN (1)
  17349.     
  17350. go
  17351. exec dbo.sp_MS_marksystemobject sp_addmergealternatepublisher 
  17352. go
  17353. grant exec on dbo.sp_addmergealternatepublisher to public
  17354. go
  17355.  
  17356. raiserror('Creating procedure sp_helpmergealternatepublisher', 0,1)
  17357. GO
  17358. CREATE PROCEDURE sp_helpmergealternatepublisher (
  17359.     @publisher                    sysname,                     /* Publisher server */
  17360.     @publisher_db               sysname,                     /* Publisher database */
  17361.     @publication                sysname                     /* Publication name */
  17362.     ) AS
  17363.  
  17364.     SET NOCOUNT ON
  17365.     declare @subid                uniqueidentifier
  17366.     declare @pubid                uniqueidentifier
  17367.     declare @distributor        sysname
  17368.     declare @retcode            int
  17369.     declare @MShelpmergealternatepublisher TABLE
  17370.     (
  17371.         subid                    uniqueidentifier     not null,
  17372.         alternate_publisher     sysname             collate database_default not null,   
  17373.         alternate_publisher_db     sysname             collate database_default not null,   
  17374.         alternate_publication     sysname             collate database_default not null,   
  17375.         alternate_distributor     sysname             collate database_default null,   
  17376.         friendly_name             nvarchar(255)         collate database_default null,   
  17377.         enabled                    bit                 not null
  17378.     )
  17379.     
  17380.     /*
  17381.     ** Select the subscription's pubid and subid
  17382.     */
  17383.     select @pubid = pubid from sysmergepublications  
  17384.                    where name = @publication and
  17385.                        LOWER(publisher) = LOWER(@publisher) and
  17386.                        publisher_db = @publisher_db
  17387.     if @pubid is NULL
  17388.         begin
  17389.             raiserror (20026, 11, -1, @publication)
  17390.             return (1)
  17391.         end
  17392.     select @subid = subid, @distributor = distributor from sysmergesubscriptions  where 
  17393.         LOWER(subscriber_server) = LOWER(@publisher) and db_name = @publisher_db and pubid = @pubid
  17394.     IF @@ERROR <> 0 
  17395.         BEGIN
  17396.             GOTO FAILURE
  17397.         END
  17398.  
  17399.     -- security check
  17400.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @pubid = @pubid
  17401.     if @retcode<>0 or @@ERROR<>0
  17402.         return (1)
  17403.     
  17404.         
  17405.     insert into @MShelpmergealternatepublisher (subid, alternate_publisher, alternate_publisher_db, alternate_publication, alternate_distributor, friendly_name, enabled)
  17406.     select distinct subs.subid,
  17407.         subs.subscriber_server, 
  17408.         subs.db_name, 
  17409.         subs.publication,
  17410.         subs.distributor,
  17411.         subs.description,
  17412.         1 from sysmergesubscriptions subs
  17413.                    where subs.subid in (select alternate_subid from MSmerge_altsyncpartners where subid = @subid)
  17414.     /* select the parent publisher */                       
  17415.     insert into @MShelpmergealternatepublisher (subid, alternate_publisher, alternate_publisher_db, alternate_publication, alternate_distributor, friendly_name, enabled)
  17416.     select distinct  pubs.pubid,
  17417.         pubs.publisher, 
  17418.         pubs.publisher_db, 
  17419.         pubs.name,
  17420.         @distributor,
  17421.         pubs.description,
  17422.         1 from sysmergepublications pubs
  17423.                    where pubs.name = @publication and
  17424.                        LOWER(publisher) = LOWER(@publisher) and
  17425.                        publisher_db = @publisher_db 
  17426.  
  17427.     insert into @MShelpmergealternatepublisher (subid, alternate_publisher, alternate_publisher_db, alternate_publication, alternate_distributor, friendly_name, enabled)
  17428.        select distinct  subs.subid,
  17429.            subs.subscriber_server, 
  17430.         subs.db_name, 
  17431.         subs.publication,
  17432.         subs.distributor,
  17433.         subs.description,
  17434.         0
  17435.         from sysmergesubscriptions subs
  17436.                where subs.subscriber_type = 1 -- only publisher and republishers
  17437.                    and subs.subid = subs.pubid -- only publisher and republishers
  17438.                    and subs.subid not in (select subid from @MShelpmergealternatepublisher)
  17439.         
  17440.     select distinct alternate_publisher,
  17441.         alternate_publisher_db,
  17442.         alternate_publication,
  17443.         alternate_distributor,
  17444.         friendly_name,
  17445.         enabled    
  17446.         from @MShelpmergealternatepublisher 
  17447.     order by alternate_publisher, alternate_publisher_db, alternate_publication, alternate_distributor
  17448.     
  17449.     return (0)
  17450. FAILURE:
  17451.     
  17452.     RETURN (1)
  17453. go
  17454. exec dbo.sp_MS_marksystemobject sp_helpmergealternatepublisher 
  17455. go
  17456. grant exec on dbo.sp_helpmergealternatepublisher to public
  17457. go
  17458.  
  17459.  
  17460. raiserror('Creating procedure sp_dropmergealternatepublisher', 0,1)
  17461. GO
  17462. CREATE PROCEDURE sp_dropmergealternatepublisher (
  17463.     @publisher                    sysname,                     /* Publisher server */
  17464.     @publisher_db               sysname,                     /* Publisher database */
  17465.     @publication                sysname,                    /* Publication name */
  17466.     @alternate_publisher        sysname,                    /* Alternate publisher */
  17467.     @alternate_publisher_db     sysname,                    /* Alternate publisher_db */
  17468.     @alternate_publication        sysname                        /* Alternate publication */
  17469.     ) AS
  17470.  
  17471.     SET NOCOUNT ON
  17472.     declare @retcode                 int
  17473.     declare @subid                    uniqueidentifier
  17474.     declare @alternate_subid        uniqueidentifier
  17475.     
  17476.     /*
  17477.     ** Security Check
  17478.     */
  17479.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  17480.     IF @@ERROR <> 0 or @retcode <> 0
  17481.         return (1)
  17482.  
  17483.     /* Check is there is an invalid attempt to drop the default publiser/publisher_db/publication */
  17484.     if (LOWER(@publisher) = LOWER(@alternate_publisher)) AND
  17485.         (@publisher_db = @alternate_publisher_db) AND
  17486.         (@publication = @alternate_publication)
  17487.         begin
  17488.             RAISERROR(21252, 11, -1,  @alternate_publisher, @alternate_publisher_db, @alternate_publication)
  17489.             return (1)
  17490.         end
  17491.  
  17492.     select @subid = subid from sysmergesubscriptions  
  17493.         where LOWER(subscriber_server) = LOWER(@publisher) and db_name = @publisher_db and publication = @publication
  17494.     /*
  17495.     ** Select the alternate publisher's subid 
  17496.     */
  17497.     select @alternate_subid = subid from sysmergesubscriptions
  17498.         where publication = @alternate_publication
  17499.         and LOWER(subscriber_server) = LOWER(@alternate_publisher) and db_name = @alternate_publisher_db
  17500.     IF @subid is NULL or @alternate_subid IS NULL
  17501.         BEGIN
  17502.             RAISERROR(21216, 11, -1,  @alternate_publisher, @alternate_publisher_db, @alternate_publication)
  17503.             RETURN (1)
  17504.         END
  17505.  
  17506.  
  17507.     if exists (select * from MSmerge_altsyncpartners where subid = @subid and alternate_subid = @alternate_subid)
  17508.         begin
  17509.             delete from MSmerge_altsyncpartners where @subid = subid and alternate_subid = @alternate_subid
  17510.             if @@ERROR <> 0 or @@rowcount <> 1
  17511.                 BEGIN
  17512.                     GOTO FAILURE
  17513.                 END
  17514.         end                
  17515.     return (0)
  17516.  
  17517. FAILURE:
  17518.     RAISERROR(21251, 11, -1,  @alternate_publisher, @alternate_publisher_db, @alternate_publication)
  17519.     RETURN (1)
  17520. go
  17521.  
  17522. exec dbo.sp_MS_marksystemobject sp_dropmergealternatepublisher 
  17523. go
  17524. grant exec on dbo.sp_dropmergealternatepublisher to public
  17525. go
  17526.  
  17527. raiserror(15339,-1,-1,'sp_MScomputemergearticlescreationorder')
  17528. GO
  17529. CREATE PROCEDURE sp_MScomputemergearticlescreationorder
  17530.     @publication sysname
  17531. AS
  17532.     SET NOCOUNT ON
  17533.     DECLARE @pubid uniqueidentifier 
  17534.     DECLARE @max_level int
  17535.     DECLARE @current_level int
  17536.     DECLARE @update_level int
  17537.     DECLARE @limit int
  17538.     DECLARE @retcode int
  17539.  
  17540.     SELECT @retcode = 0
  17541.  
  17542.     EXEC @retcode = sp_MSreplcheck_publish
  17543.     IF @@ERROR <> 0 OR @retcode <> 0
  17544.         return (1)
  17545.  
  17546.     SELECT @pubid = NULL
  17547.     -- Get the pubid from sysmergepublications 
  17548.     SELECT @pubid = pubid 
  17549.       FROM sysmergepublications
  17550.      WHERE name = @publication
  17551.        AND UPPER(publisher) = UPPER(@@SERVERNAME)
  17552.        AND publisher_db = DB_NAME()
  17553.  
  17554.     IF @@ERROR <> 0
  17555.         RETURN (1)
  17556.  
  17557.     IF @pubid IS NULL
  17558.     BEGIN
  17559.         RAISERROR(20026, 16, -1, @publication)
  17560.         RETURN (1)
  17561.     END
  17562.  
  17563.     -- Find out the total number of articles in this publication and
  17564.     -- compute the maximum tree height based on the number of articles in 
  17565.     -- the publication. Here, the tree height is counted from the
  17566.     -- leaf-nodes towards the root(s) starting from @max_level
  17567.     SELECT @max_level = COUNT(*) + 10,
  17568.            @limit = 2 * COUNT(*) + 11 
  17569.       FROM sysmergeextendedarticlesview 
  17570.      WHERE pubid = @pubid
  17571.  
  17572.     IF @@ERROR <> 0
  17573.     BEGIN
  17574.         RETURN (1)
  17575.     END
  17576.    
  17577.     -- The following temp table contains the minimal amount of 
  17578.     -- article information that we want to keep around and the current
  17579.     -- computed tree level of the article
  17580.     CREATE TABLE #article_level_info
  17581.     (
  17582.         article         sysname collate database_default not null,
  17583.         source_objid    INT     NOT NULL,
  17584.         tree_level      INT     NOT NULL,
  17585.         nickname        INT     NOT NULL,
  17586.         major_type      TINYINT NOT NULL  -- 1-view&func, 0-other
  17587.     )  
  17588.    
  17589.     CREATE CLUSTERED INDEX ucarticle_level_info 
  17590.         ON #article_level_info(source_objid)
  17591.  
  17592.     IF @@ERROR <> 0
  17593.     BEGIN
  17594.         GOTO Failure
  17595.     END
  17596.  
  17597.     -- Populate the article level info table. All articles will be
  17598.     -- assigned 0 as their initial tree level. Having 
  17599.     -- a tree level of 0 means that the algorithm hasn't discovered 
  17600.     -- any objects that the article depends on within the publication.
  17601.  
  17602.     INSERT INTO #article_level_info 
  17603.     SELECT name, objid, 0, ISNULL(nickname, 5*@max_level),
  17604.         CASE type
  17605.             WHEN 0x40 THEN 1
  17606.             WHEN 0x80 THEN 1
  17607.             ELSE 0
  17608.         END 
  17609.       FROM sysmergeextendedarticlesview
  17610.      WHERE pubid = @pubid
  17611.       
  17612.     -- To jump-start the algorithm, update the tree_level of 
  17613.     -- all articles with no dependency to @max_level.
  17614.  
  17615.     UPDATE #article_level_info 
  17616.        SET tree_level = @max_level
  17617.      WHERE NOT EXISTS (SELECT * 
  17618.                          FROM sysdepends 
  17619.                         WHERE source_objid = id
  17620.                           AND id <> depid)
  17621.     IF @@ERROR <> 0
  17622.         GOTO Failure
  17623.  
  17624.     -- For each increasing tree level starting from @max_level, update the 
  17625.     -- the tree_level of articles depending on objects at the current
  17626.     -- level to current level + 1
  17627.     SELECT @current_level = @max_level
  17628.     WHILE 1 = 1
  17629.     BEGIN
  17630.         SELECT @update_level = @current_level + 1
  17631.  
  17632.         UPDATE #article_level_info
  17633.            SET tree_level = @update_level
  17634.           FROM #article_level_info 
  17635.         INNER JOIN sysdepends d
  17636.             ON #article_level_info.source_objid = d.id 
  17637.         INNER JOIN #article_level_info ali1
  17638.             ON (d.depid = ali1.source_objid       
  17639.                AND ali1.tree_level = @current_level
  17640.                AND d.id <> d.depid)
  17641.     
  17642.         -- Terminate the algorithm if we cannot find any articles 
  17643.         -- depending on articles at the current level     
  17644.         IF @@ROWCOUNT = 0
  17645.             GOTO PHASE1
  17646.  
  17647.         IF @@ERROR <> 0
  17648.             GOTO Failure
  17649.  
  17650.         SELECT @current_level = @current_level + 1
  17651.  
  17652.         -- Although there should not be any circular 
  17653.         -- dependencies among the articles, the following
  17654.         -- check is performed to guarantee that 
  17655.         -- the algorithm will terminate even if there 
  17656.         -- is circular dependency among the articles
  17657.         
  17658.         -- Note that with at least one node per level,
  17659.         -- the current level can never exceed the total 
  17660.         -- number of articles (nodes) unless there is
  17661.         -- circular dependency among the articles.
  17662.         
  17663.         -- @limit is defined to be # of articles + 1
  17664.         -- although @limit = # of articles - 1 will be
  17665.         -- sufficient. This is to make absolutely sure that 
  17666.         -- the algorithm will never terminate too early
  17667.  
  17668.         IF @current_level > @limit
  17669.             GOTO PHASE1
  17670.     END
  17671.  
  17672. PHASE1:
  17673.     
  17674.     -- There may be interdependencies among articles 
  17675.     -- that haven't been included in the previous calculations so
  17676.     -- we compute the proper order among these articles here.
  17677.     SELECT @limit = @max_level - 9
  17678.     SELECT @current_level = 0
  17679.     WHILE 1 = 1
  17680.     BEGIN
  17681.         SELECT @update_level = @current_level + 1
  17682.         
  17683.         UPDATE #article_level_info 
  17684.            SET tree_level = @update_level
  17685.           FROM #article_level_info
  17686.         INNER JOIN sysdepends d
  17687.             ON (#article_level_info.source_objid = d.id
  17688.                 AND #article_level_info.tree_level < @max_level) 
  17689.         INNER JOIN #article_level_info ali1
  17690.             ON (d.depid = ali1.source_objid
  17691.                 AND ali1.tree_level = @current_level
  17692.                 AND d.id <> d.depid)
  17693.         IF @@ROWCOUNT = 0
  17694.             GOTO PHASE2
  17695.         
  17696.         IF @@ERROR <> 0
  17697.             GOTO Failure
  17698.  
  17699.         SELECT @current_level = @current_level + 1
  17700.         IF @current_level > @limit
  17701.             GOTO PHASE2
  17702.     END         
  17703.  
  17704. PHASE2:
  17705.  
  17706.     -- Select the articles out of #article_level_info 
  17707.     -- in ascending order of tree_level. This will give
  17708.     -- the proper order in which articles can be created
  17709.     -- without violating the internal dependencies among
  17710.     -- the themselves. Note that this algorithm still allows 
  17711.     -- unresolved external references outside the publication.
  17712.     -- All this algorithm can guarantee is that all articles will
  17713.     -- be created successfully using the resulting order if 
  17714.     -- there is no dependent object outside the publication. 
  17715.  
  17716.     SELECT article
  17717.       FROM #article_level_info
  17718.     ORDER BY major_type ASC, tree_level ASC, nickname ASC
  17719.  
  17720.     DROP TABLE #article_level_info
  17721.     RETURN (0)
  17722.  
  17723. Failure:
  17724.  
  17725.     DROP TABLE #article_level_info
  17726.     RETURN (1)
  17727. GO
  17728.  
  17729. exec dbo.sp_MS_marksystemobject sp_MScomputemergearticlescreationorder
  17730. go
  17731. grant exec on dbo.sp_MScomputemergearticlescreationorder to public
  17732. go
  17733.  
  17734. raiserror(15339,-1,-1,'sp_MScomputemergeunresolvedrefs')
  17735. GO
  17736. CREATE PROCEDURE sp_MScomputemergeunresolvedrefs
  17737.     @publication sysname, -- Must provide the publication name
  17738.     @article     sysname = '%' -- '%' means all articles in the specified publication, otherwise an exact match is performed
  17739. AS
  17740.     SET NOCOUNT ON 
  17741.     DECLARE @pubid uniqueidentifier 
  17742.  
  17743.     
  17744.     -- Parameter check: @publication
  17745.  
  17746.     IF @publication IS NULL
  17747.     BEGIN
  17748.         RAISERROR (14043, 16, -1, '@publication')
  17749.         RETURN (1)
  17750.     END
  17751.  
  17752.     SELECT @pubid = NULL 
  17753.     -- Get the pubid of the publication
  17754.     SELECT @pubid = pubid 
  17755.       FROM sysmergepublications
  17756.      WHERE name = @publication
  17757.        AND UPPER(publisher) = UPPER(@@SERVERNAME)
  17758.        AND publisher_db = DB_NAME()
  17759.     
  17760.     IF @pubid IS NULL
  17761.     BEGIN
  17762.         RAISERROR (20026, 11, -1, @publication)
  17763.         RETURN (1)    
  17764.     END
  17765.  
  17766.     if ({ fn ISPALUSER(@pubid) } <> 1)
  17767.     begin    
  17768.         RAISERROR (14126, 11, -1)
  17769.         return (1)
  17770.  
  17771.     end    
  17772.  
  17773.     SELECT DISTINCT 
  17774.            'article' = a.name, 
  17775.            'dependent object' = o.name, 
  17776.            'dependent object owner' = u.name, 
  17777.            'dependent objectid' = o.id 
  17778.       FROM dbo.sysmergeextendedarticlesview a
  17779.     INNER JOIN sysdepends dep
  17780.         ON a.objid = dep.id
  17781.        AND a.pubid = @pubid
  17782.        AND (@article = '%' OR name = @article)
  17783.        AND dep.depid NOT IN (SELECT objid FROM dbo.sysmergeextendedarticlesview
  17784.                               WHERE pubid = @pubid 
  17785.                                 AND (@article = '%' OR name = @article))
  17786.     INNER JOIN sysobjects o
  17787.         ON dep.depid = o.id
  17788.     INNER JOIN sysusers u
  17789.         ON u.uid = o.uid          
  17790. GO
  17791.  
  17792. exec dbo.sp_MS_marksystemobject sp_MScomputemergeunresolvedrefs
  17793. go
  17794. grant exec on dbo.sp_MScomputemergeunresolvedrefs to public
  17795. go
  17796.  
  17797. raiserror('Creating procedure sp_MSCheckmergereplication', 0,1)
  17798. GO
  17799.  
  17800. CREATE PROCEDURE sp_MSCheckmergereplication
  17801. AS
  17802.     SET NOCOUNT ON
  17803.     declare @category int
  17804.     declare @db_name sysname
  17805.  
  17806.     select @db_name=db_name()
  17807.     select @category=category FROM master..sysdatabases WHERE name = @db_name collate database_default
  17808.     if @category & 4 = 0
  17809.         begin
  17810.             raiserror(21147, 16, -1, @db_name)
  17811.             return (1)
  17812.         end
  17813.     return (0)    
  17814. go
  17815. exec dbo.sp_MS_marksystemobject sp_MSCheckmergereplication
  17816. go
  17817.  
  17818.  
  17819. raiserror('Creating procedure sp_MSgetpubinfo', 0,1)
  17820. GO
  17821.  
  17822. CREATE PROCEDURE sp_MSgetpubinfo (
  17823.     @publication    sysname,    /* The publication name */
  17824.     @publisher        sysname,
  17825.     @pubdb            sysname
  17826.     ) AS
  17827.  
  17828.     SET NOCOUNT ON
  17829.  
  17830.     --don't further qualify with server name and DB name - it's just security checking
  17831.     if not exists (select * from dbo.sysmergepublications 
  17832.                             where 1 = {fn ISPALUSER(pubid)})
  17833.     begin    
  17834.         RAISERROR (14126, 11, -1)
  17835.         return (1)
  17836.     end
  17837.  
  17838.     select pubid from sysmergepublications where name = @publication and
  17839.             LOWER(publisher) = LOWER(@publisher) and LOWER(publisher_db) = LOWER(@pubdb)
  17840.             
  17841. go
  17842. exec dbo.sp_MS_marksystemobject sp_MSgetpubinfo
  17843. go
  17844.  
  17845. grant execute on dbo.sp_MSgetpubinfo to public
  17846. go
  17847.  
  17848. raiserror('Creating procedure sp_MSaddmergedynamicsnapshotjob', 0,1)
  17849. go
  17850. --
  17851. -- Name: sp_MSaddmergedynamicsnapshotjob
  17852. --
  17853. -- Description: This procedure sets up a SQL Server Agent job for dynamic 
  17854. --              snapshot generation and associates a row in 
  17855. --              MSdynamicsnapshotjobs for the job to the specified publication.
  17856. --
  17857. -- Notes: 1) If a local path is specified for the @dynamic_snapshot_location,
  17858. --           the local path of the Distribution server will be used. 
  17859. --        2) This procedure will not check whether the given path is already in
  17860. --           use by another dynamic snapshot generation job. Sharing the same
  17861. --           dynamic snapshot location among different dynamic snapshot 
  17862. --           generation jobs can lead to file corruption and/or snapshot files 
  17863. --           being overwritten.  
  17864. --        3) A regular snapshot job must be added for the publication before
  17865. --           a dynamic snapshot generation job can be scheduled.
  17866. --        4) This procedure will not check for the existence of the given
  17867. --           dynamic snapshot location.
  17868. --        5) The specified publication must be enabled for dynamic filtering.
  17869. --        6) If @dynamic_snapshot_jobname is specified, it must be unique 
  17870. --           among all the jobs at the distributor's msdb. If it is left
  17871. --           unspecified, a job name will be generated according to the
  17872. --           following rule:
  17873. --           'dyn_' + (job name for the regular snapshot job) + (guid string)
  17874. --           Note that (job name for the regular snapshot job) can be truncated
  17875. --           if the resulting name is too long.
  17876. -- 
  17877. -- Parameters: @publication sysname (mandatory)
  17878. --             @dynamic_filter_login sysname (optional, default null)
  17879. --             @dynamic_filter_hostname sysname (optional, default null)
  17880. --             @dynamic_snapshot_location nvarchar(255) (mandatory)
  17881. --             @dynamic_snapshot_jobid (optional, output, default null)
  17882. --             @dynamic_snapshot_jobname (optional, output, default null)
  17883. --             Scheduling information:
  17884. --             @frequency_type int (optional, default 4 == Daily)
  17885. --             @frequency_interval int (optional, default 1 == Every day)
  17886. --             @frequency_subday int (optional, default 4 (Sub interval = Minute))
  17887. --             @frequency_subday_interval int (optional, default 5 == Every five minutes)
  17888. --             @frequency_relative_interval int (optional, default 1) 
  17889. --             @frequency_recurrence_factor int (optional, default 0) 
  17890. --             @active_start_date int (optional, default 0 == Today)
  17891. --             @active_end_date int (optional, default 99991231) 
  17892. --             @active_start_time_of_day int (optional, default 0 == Now)
  17893. --             @active_end_time_of_day int (optional, default 235959)
  17894. --
  17895. -- Returns: 0 - succeeded
  17896. --          1 - failed
  17897. --
  17898. -- Result set (upon successful completion of the operation):
  17899. --          dynamic_snapshot_jobname sysname
  17900. --          dynamic_snapshot_jobid uniqueidentifier
  17901. -- Security: Only members of the 'sysadmin' server role and members of the
  17902. --           'db_owner' database role can invoke this procedure successfully.
  17903. --           Security check is performed inside the procedure.
  17904. --
  17905. create procedure sp_MSaddmergedynamicsnapshotjob (
  17906.     @publication sysname,
  17907.     @dynamic_filter_login sysname = null,
  17908.     @dynamic_filter_hostname sysname = null,
  17909.     @dynamic_snapshot_location nvarchar(255), 
  17910.     @dynamic_snapshot_jobname sysname = null output,
  17911.     @dynamic_snapshot_jobid uniqueidentifier = null output,
  17912.  
  17913.     -- Scheduling information
  17914.     @frequency_type              int = 4,
  17915.     @frequency_interval          int = 1,
  17916.     @frequency_subday            int = 4,
  17917.     @frequency_subday_interval   int = 5,
  17918.     @frequency_relative_interval int = 1, 
  17919.     @frequency_recurrence_factor int = 0,
  17920.     @active_start_date           int = 0,
  17921.     @active_end_date             int = 99991231,
  17922.     @active_start_time_of_day    int = 0, 
  17923.     @active_end_time_of_day      int = 235959
  17924.     )
  17925. as
  17926. begin
  17927.     set nocount on
  17928.  
  17929.     declare @retcode int
  17930.     declare @pubid uniqueidentifier
  17931.     declare @dynamic_filters bit
  17932.     declare @snapshot_jobid uniqueidentifier 
  17933.     declare @command_line nvarchar(4000)
  17934.     declare @distribdb sysname
  17935.     declare @rpcsrvname sysname
  17936.     declare @distributor sysname
  17937.     declare @fjobcreated bit
  17938.     declare @distproc nvarchar(4000)
  17939.     declare @id int 
  17940.  
  17941.     -- Initializations
  17942.     select @retcode = 0
  17943.     select @pubid = null
  17944.     select @dynamic_filters = 0
  17945.     select @snapshot_jobid = null
  17946.     select @fjobcreated = 0
  17947.  
  17948.     if not exists (select * from sysobjects where name = 'sysmergepublications')
  17949.     begin
  17950.         raiserror (20054, 16, -1)
  17951.         return (1)
  17952.     end
  17953.  
  17954.     -- Make sure that caller is a member of 'sysadmins' or 'db_owner'
  17955.     exec @retcode = dbo.sp_MSreplcheck_publish
  17956.     if @@error <> 0 or @retcode <> 0
  17957.         return (1)
  17958.     
  17959.     -- Check that the given dynammic filter login is in the PAL
  17960.     exec @retcode = sp_check_publication_access
  17961.         @publication = @publication,
  17962.         @given_login = @dynamic_filter_login
  17963.     if @retcode <> 0 or @@error <> 0
  17964.         return 1
  17965.  
  17966.     select @dynamic_snapshot_location = ltrim(@dynamic_snapshot_location)
  17967.     -- Specified @dynamic_snapshot_location must be non-empty
  17968.     if @dynamic_snapshot_location is null or 
  17969.        @dynamic_snapshot_location = N''
  17970.     begin
  17971.         raiserror(21321, 16, -1)         
  17972.         return (1)
  17973.     end
  17974.  
  17975.     -- Verify that the given publication exists and get the pubid at the
  17976.     -- same time
  17977.     select @pubid = pubid,
  17978.            @dynamic_filters = dynamic_filters
  17979.       from dbo.sysmergepublications
  17980.      where upper(publisher) = upper(@@servername)
  17981.        and publisher_db = db_name()
  17982.        and name = @publication
  17983.  
  17984.     if @pubid is null
  17985.     begin
  17986.         raiserror(20026, 16, -1, @publication) 
  17987.         return (1)        
  17988.     end
  17989.  
  17990.     -- The given publication must be enabled for dynamic filtering
  17991.     if @dynamic_filters <> 1
  17992.     begin
  17993.         raiserror(21323, 16, -1)
  17994.         return (1)
  17995.     end
  17996.  
  17997.     -- A regular snapshot job is required before a dynamic snapshot job
  17998.     -- can be scheduled
  17999.     select @snapshot_jobid = snapshot_jobid from MSmerge_replinfo
  18000.      where repid = @pubid
  18001.  
  18002.     if @snapshot_jobid is null
  18003.     begin
  18004.         raiserror(21324, 16, -1)            
  18005.         return (1)
  18006.     end
  18007.  
  18008.     -- The given dynamic snapshot job name cannot be '%' and it cannot match
  18009.     -- any of the existing dynamic snapshot job name
  18010.     if @dynamic_snapshot_jobname = '%'
  18011.     begin
  18012.         raiserror(21327, 16, -1)
  18013.         return (1)
  18014.     end
  18015.  
  18016.     if exists (select * 
  18017.                  from MSdynamicsnapshotjobs 
  18018.                 where name = @dynamic_snapshot_jobname)
  18019.     begin
  18020.         raiserror(21328, 16, -1, @dynamic_snapshot_jobname)
  18021.         return (1)
  18022.     end    
  18023.  
  18024.  
  18025.     -- Get distributor information for RPC
  18026.     exec @retcode = sp_helpdistributor @distributor = @distributor output,
  18027.                                        @distribdb = @distribdb output,
  18028.                                        @rpcsrvname = @rpcsrvname output
  18029.     if @@error <> 0 or @retcode <> 0
  18030.         return (1)
  18031.  
  18032.     select @distproc = rtrim(@rpcsrvname) + N'.' + @distribdb + N'.' + N'dbo.sp_MSadddynamicsnapshotjobatdistributor'
  18033.  
  18034.     exec @retcode = @distproc 
  18035.         @regular_snapshot_jobid = @snapshot_jobid,
  18036.         @dynamic_filter_login = @dynamic_filter_login,
  18037.         @dynamic_filter_hostname = @dynamic_filter_hostname,
  18038.         @dynamic_snapshot_location = @dynamic_snapshot_location,
  18039.         @dynamic_snapshot_jobname = @dynamic_snapshot_jobname output,
  18040.         @dynamic_snapshot_jobid = @dynamic_snapshot_jobid output,
  18041.         @freqtype = @frequency_type,
  18042.         @freqinterval = @frequency_interval,
  18043.         @freqsubtype = @frequency_subday,
  18044.         @freqsubinterval = @frequency_subday_interval,
  18045.         @freqrelativeinterval = @frequency_relative_interval,
  18046.         @freqrecurrencefactor = @frequency_recurrence_factor,
  18047.         @activestartdate = @active_start_date,
  18048.         @activeenddate = @active_end_date,
  18049.         @activestarttimeofday = @active_start_time_of_day,
  18050.         @activeendtimeofday = @active_end_time_of_day
  18051.     
  18052.     if @retcode <> 0 or @@error <> 0
  18053.         goto Failure
  18054.  
  18055.     select @fjobcreated = 1
  18056.  
  18057.     insert MSdynamicsnapshotjobs 
  18058.     (name, pubid, job_id, dynamic_filter_login, dynamic_filter_hostname, 
  18059.      dynamic_snapshot_location)
  18060.     values
  18061.     (@dynamic_snapshot_jobname, @pubid, @dynamic_snapshot_jobid, 
  18062.      @dynamic_filter_login, @dynamic_filter_hostname, 
  18063.      @dynamic_snapshot_location)    
  18064.     
  18065.     if @@error <> 0
  18066.     begin
  18067.         goto Failure
  18068.     end
  18069.  
  18070.     select @id = @@identity    
  18071.  
  18072.     select 'id'                       = @id,
  18073.            'dynamic_snapshot_jobname' = @dynamic_snapshot_jobname,
  18074.            'dynamic_snapshot_jobid' = @dynamic_snapshot_jobid
  18075.     return 0
  18076.  
  18077. Failure:
  18078.     if @fjobcreated = 1
  18079.     begin
  18080.         select @distproc = rtrim(@rpcsrvname) + N'.' + @distribdb + N'.' + N'dbo.sp_MSdeleterepljob'
  18081.         exec @distproc @job_id = @dynamic_snapshot_jobid
  18082.     end
  18083.     return @retcode
  18084. end
  18085. go
  18086. exec dbo.sp_MS_marksystemobject sp_MSaddmergedynamicsnapshotjob
  18087. go
  18088.  
  18089. grant execute on dbo.sp_MSaddmergedynamicsnapshotjob to public
  18090. go
  18091.  
  18092.  
  18093. raiserror('Creating procedure sp_MSdropmergedynamicsnapshotjob', 0,1)
  18094. go
  18095. --
  18096. -- Name: sp_MSdropmergedynamicsnapshotjob
  18097. --
  18098. -- Description: This procedure drops a scheduled dynamic snapshot job for
  18099. --              a publication and the associated meta-data in 
  18100. --              MSdynamicsnapshotjobs. This procedure will also remove all 
  18101. --              files in the associated dynamic snapshot location.
  18102. --
  18103. -- Parameters: @publication sysname (mandatory)
  18104. --             @dynamic_snapshot_jobname (optional, default '%')
  18105. --             @dynamic_snapshot_jobid uniqueidentifier (optional, default 
  18106. --             null) When @dynamic_snapshot_jobid is null and 
  18107. --             @dynamic_snapshot_jobname is '%', all dynamic snapshot
  18108. --             jobs for the specified publication will be dropped.
  18109. --             @ignore_distributor bit (optional, default 0) 
  18110. --
  18111. -- Notes: 1) At most one of @dynamic_snapshot_jobid and 
  18112. --           @dynamic_snapshot_jobname can be specified with a non-default 
  18113. --           value.
  18114. --           
  18115. -- Returns: 0 - succeeded
  18116. --          1 - failed
  18117. --
  18118. -- Security: Only members of the 'sysadmin' server role and the 'db_owner'  
  18119. -- database role can execute this procedure successfully even though execute
  18120. -- permission of this procedure is granted to public.
  18121. --
  18122. create procedure sp_MSdropmergedynamicsnapshotjob (
  18123.     @publication sysname,
  18124.     @dynamic_snapshot_jobname sysname = '%',
  18125.     @dynamic_snapshot_jobid uniqueidentifier = null,
  18126.     @ignore_distributor bit = 0
  18127.     )
  18128. as
  18129. begin
  18130.     set nocount on
  18131.     
  18132.     declare @retcode int
  18133.     declare @pubid uniqueidentifier
  18134.     declare @dynamic_snapshot_location nvarchar(255)
  18135.     declare @guidstr nvarchar(40)
  18136.     declare @dynamic_snapshot_jobid_from_cursor uniqueidentifier
  18137.  
  18138.     declare @distributor sysname
  18139.     declare @distribdb sysname
  18140.     declare @rpcsrvname sysname
  18141.     declare @distproc nvarchar(4000)
  18142.  
  18143.     select @retcode = 0
  18144.     select @pubid = null
  18145.     select @dynamic_snapshot_location = null
  18146.  
  18147.  
  18148.     if not exists (select * from sysobjects where name = 'sysmergepublications')
  18149.     begin
  18150.         raiserror (20054, 16, -1)
  18151.         return (1)
  18152.     end
  18153.  
  18154.     -- Make sure that caller is a member of 'sysadmins' or 'db_owner'
  18155.     exec @retcode = dbo.sp_MSreplcheck_publish
  18156.     if @@error <> 0 or @retcode <> 0
  18157.         return (1)
  18158.  
  18159.     select @pubid = pubid 
  18160.       from dbo.sysmergepublications 
  18161.      where name = @publication
  18162.        and upper(publisher) = upper(@@servername)
  18163.        and publisher_db = db_name()
  18164.   
  18165.     if @pubid is null
  18166.     begin
  18167.         raiserror(20026, 16, -1, @publication)
  18168.         return (1)
  18169.     end
  18170.     
  18171.     -- At most one of @dynamic_snapshot_jobid and @dynamic_snapshot_jobname
  18172.     -- can be specified with a non-default value
  18173.     if @dynamic_snapshot_jobid is not null and
  18174.        @dynamic_snapshot_jobname <> N'%'
  18175.     begin
  18176.         raiserror(21329, 16, -1)
  18177.         return (1)
  18178.     end
  18179.  
  18180.     if @dynamic_snapshot_jobid is null and @dynamic_snapshot_jobname = N'%'
  18181.     begin
  18182.  
  18183.         declare hJobsCursor cursor local fast_forward for
  18184.             select job_id 
  18185.               from MSdynamicsnapshotjobs 
  18186.              where pubid = @pubid
  18187.         if @@error <> 0
  18188.             return 1
  18189.  
  18190.         open hJobsCursor 
  18191.         if @@error <> 0
  18192.             return 1
  18193.             
  18194.  
  18195.         fetch hJobsCursor into @dynamic_snapshot_jobid_from_cursor 
  18196.           
  18197.         begin transaction
  18198.         save transaction sp_MSdropdynamicsnapshotjobC
  18199.             
  18200.         while (@@fetch_status <> -1)
  18201.         begin
  18202.             if @dynamic_snapshot_jobid_from_cursor is not null
  18203.             begin
  18204.                 exec @retcode = sp_MSdropmergedynamicsnapshotjob 
  18205.                     @publication = @publication,
  18206.                     @dynamic_snapshot_jobid = @dynamic_snapshot_jobid_from_cursor,
  18207.                     @ignore_distributor = @ignore_distributor
  18208.                 if @@error <> 0 or @retcode <> 0
  18209.                     goto CursorFailure
  18210.             end
  18211.             fetch hJobsCursor into @dynamic_snapshot_jobid_from_cursor
  18212.         end                
  18213.  
  18214.         commit transaction
  18215.         close hJobsCursor
  18216.         deallocate hJobsCursor        
  18217.         return 0
  18218. CursorFailure:
  18219.  
  18220.  
  18221.         rollback transaction sp_MSdropdynamicsnapshotjobC
  18222.         commit transaction
  18223.         close hJobsCursor
  18224.         deallocate hJobsCursor
  18225.         return 1
  18226.     end
  18227.  
  18228.     select @pubid = pubid 
  18229.       from dbo.sysmergepublications 
  18230.      where name = @publication
  18231.        and upper(publisher) = upper(@@servername)
  18232.        and publisher_db = db_name()
  18233.  
  18234.     if @dynamic_snapshot_jobid is null
  18235.     begin   
  18236.         select @dynamic_snapshot_location = dynamic_snapshot_location,
  18237.                @dynamic_snapshot_jobid = job_id
  18238.           from dbo.MSdynamicsnapshotjobs
  18239.          where pubid = @pubid
  18240.            and name = @dynamic_snapshot_jobname 
  18241.     end
  18242.     else 
  18243.     begin
  18244.         select @dynamic_snapshot_location = dynamic_snapshot_location 
  18245.           from dbo.MSdynamicsnapshotjobs
  18246.          where pubid = @pubid
  18247.            and job_id = @dynamic_snapshot_jobid 
  18248.     end
  18249.  
  18250.     if @dynamic_snapshot_location is null
  18251.     begin
  18252.         if @dynamic_snapshot_jobid is null
  18253.         begin
  18254.             raiserror(21326, 16, -1, N'@dynamic_snapshot_jobname', @dynamic_snapshot_jobname)
  18255.         end
  18256.         else
  18257.         begin
  18258.             select @guidstr = coalesce(convert(nvarchar(40), @dynamic_snapshot_jobid) collate database_default, '(NULL)' collate database_default)
  18259.             raiserror(21326, 16, -1, N'@dynamic_snapshot_jobid', @guidstr)
  18260.         end
  18261.         return (1)        
  18262.     end
  18263.  
  18264.     -- Get distributor info for RPC
  18265.     if @ignore_distributor = 0
  18266.     begin
  18267.         exec @retcode = sp_helpdistributor @distributor = @distributor output,
  18268.                                            @distribdb = @distribdb output,
  18269.                                            @rpcsrvname = @rpcsrvname output
  18270.     
  18271.         select @rpcsrvname = rtrim(@rpcsrvname)
  18272.     
  18273.         select @distproc = @rpcsrvname + N'.' + @distribdb + N'.' + N'dbo.sp_MSdeletefoldercontents'
  18274.         -- Try to delete the files 
  18275.         exec @retcode = @distproc @dynamic_snapshot_location
  18276.         -- Ignore errors 
  18277.     end    
  18278.     select @retcode = 0
  18279.  
  18280.     begin transaction 
  18281.     save transaction sp_MSdropmergedynamicsnapshotjob
  18282.  
  18283.     -- Delete row from MSdynamicsnapshotjobs
  18284.     delete dbo.MSdynamicsnapshotjobs 
  18285.      where pubid = @pubid
  18286.        and job_id = @dynamic_snapshot_jobid
  18287.  
  18288.     if @@error <> 0
  18289.         goto Failure
  18290.  
  18291.     if @ignore_distributor = 0
  18292.     begin
  18293.         -- Drop the dynamic snapshot job at the distributor 
  18294.         select @distproc = @rpcsrvname + N'.' + @distribdb + N'.' + N'dbo.sp_MSdeleterepljob'
  18295.  
  18296.         exec @retcode = @distproc @dynamic_snapshot_jobid
  18297.         if @retcode <> 0 or @@error <> 0
  18298.             goto Failure
  18299.     end
  18300.     commit transaction
  18301.     return 0
  18302.  
  18303. Failure:
  18304.     rollback transaction sp_MSdropmergedynamicsnapshotjob
  18305.     commit transaction
  18306.     return 1
  18307. end
  18308. go
  18309.  
  18310. exec dbo.sp_MS_marksystemobject sp_MSdropmergedynamicsnapshotjob
  18311. go
  18312. grant execute on dbo.sp_MSdropmergedynamicsnapshotjob to public
  18313. go
  18314.  
  18315. raiserror('Creating procedure sp_MShelpmergedynamicsnapshotjob', 0, 1)
  18316. go
  18317. --
  18318. -- Name: sp_MShelpmergedynamicsnapshotjob
  18319. --
  18320. -- Description: This procedure returns a listing of dynamic snapshot jobs.
  18321. --              
  18322. -- Parameters: @publication sysname (optional, default '%'): When @publication
  18323. --             is '%', all dynamic snapshot jobs with the matching 
  18324. --             @dynamic_snapshot_jobid and @dynamic_snapshot_jobname will be 
  18325. --             returned.
  18326. --             @dynamic_snapshot_jobname sysname (optional, default '%'): When 
  18327. --             @dynamic_snapshot_jobname is '%', all dynamic snapshot jobs that
  18328. --             belong to @publication with the matching @dynamic_snapshot_jobid
  18329. --             will be returned.  
  18330. --             @dynamic_snapshot_jobid (optional, default null): When 
  18331. --             @dynamic_snapshot_jobid is null, all dynamic snapshot jobs 
  18332. --             that belong to @publication with the matching 
  18333. --             @dynamic_snapshot_jobname will be returned.
  18334. --
  18335. -- Notes: If all parameters are left unspecified when this procedure is called,
  18336. --        all dynamic snapshot jobs for the current database will be returned.
  18337. --
  18338. -- Result: id int
  18339. --         job_name sysname 
  18340. --         job_id uniqueidentifier -- job id of the dynamic snapshot job
  18341. --         dynamic_filter_login sysname 
  18342. --         dynamic_filter_hostname sysname
  18343. --         dynamic_snapshot_location nvarchar(255) 
  18344. -- Returns: 0 - succeeded
  18345. --          1 - failed
  18346. --
  18347. -- Security: Execute permission of this stored procedure is granted to public
  18348. --
  18349. create procedure sp_MShelpmergedynamicsnapshotjob (
  18350.     @publication sysname = N'%',
  18351.     @dynamic_snapshot_jobname sysname = N'%',
  18352.     @dynamic_snapshot_jobid uniqueidentifier = null
  18353.     )
  18354. as
  18355. begin
  18356.     declare @retcode int
  18357.     set nocount on
  18358.     /*
  18359.     ** Security Check
  18360.     */
  18361.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  18362.     IF @@ERROR <> 0 or @retcode <> 0
  18363.         return (1)
  18364.     if not exists (select * from sysobjects where name = 'sysmergepublications')
  18365.     begin
  18366.         return 0
  18367.     end
  18368.  
  18369.     select 'id' = j.id,
  18370.            'job_name' = j.name,
  18371.            'job_id' = j.job_id, 
  18372.            'dynamic_filter_login' = j.dynamic_filter_login,
  18373.            'dynamic_filter_hostname' = j.dynamic_filter_hostname,
  18374.            'dynamic_snapshot_location' = j.dynamic_snapshot_location
  18375.       from sysmergepublications p
  18376.      inner join MSdynamicsnapshotjobs j
  18377.         on p.pubid = j.pubid
  18378.      where (p.name = @publication or @publication = N'%')
  18379.        and (j.name = @dynamic_snapshot_jobname or @dynamic_snapshot_jobname = N'%')
  18380.        and (j.job_id = @dynamic_snapshot_jobid or @dynamic_snapshot_jobid is null) 
  18381.  
  18382.     if @@error <> 0
  18383.         return (1)
  18384.     else
  18385.         return (0)
  18386.  
  18387. end
  18388. go
  18389. exec dbo.sp_MS_marksystemobject sp_MShelpmergedynamicsnapshotjob
  18390. go
  18391. grant execute on dbo.sp_MShelpmergedynamicsnapshotjob to public
  18392. go
  18393.  
  18394. create procedure sp_MSremove_userscript(
  18395. @pubid                uniqueidentifier,
  18396. @drop_publication    bit = 0
  18397. )as
  18398.     declare @retention            int
  18399.     declare @last_snapshot        datetime
  18400.     declare @post_snapshot_ver    int
  18401.     declare @post_snapshot_type    int
  18402.     declare @user_script_type    int
  18403.     declare @retcode            int
  18404.     declare @len                int
  18405.  
  18406.     declare @file_path            nvarchar(4000)
  18407.     declare @delfile_cmd        nvarchar(4000)
  18408.     declare @rmdir_cmd            nvarchar(4000)
  18409.     
  18410.     select @post_snapshot_type=52
  18411.     select @user_script_type=46
  18412.     
  18413.     if not exists (select * from sysmergeschemachange where pubid=@pubid and schematype=@user_script_type)
  18414.         return (0)
  18415.     select @retention=retention from sysmergepublications where pubid=@pubid
  18416.     select @last_snapshot=last_validated from sysmergesubscriptions where pubid=@pubid and subid=@pubid
  18417.  
  18418.     --I do not want to remove  script files by setting retention to 0
  18419.     if (@retention=0 or dateadd(day, -@retention, getdate()) < @last_snapshot) and @drop_publication = 0
  18420.         return (0)
  18421.  
  18422.     select @post_snapshot_ver=schemaversion from sysmergeschemachange 
  18423.         where schematype=@post_snapshot_type and pubid=@pubid
  18424.         
  18425.     --only get those script that can be safely removed
  18426.     
  18427.     declare #per_script cursor local fast_forward for
  18428.         select schematext from sysmergeschemachange 
  18429.             where pubid=@pubid and schematype=@user_script_type 
  18430.             and (schemaversion<@post_snapshot_ver or @drop_publication = 1)
  18431.     open #per_script
  18432.     fetch #per_script into @file_path
  18433.     while (@@fetch_status<>-1)
  18434.     begin
  18435.     if(left(@file_path, 1) = N'0' or left(@file_path, 1) = N'1')
  18436.         select @file_path = right(@file_path, len(@file_path) - 1)
  18437.         select @delfile_cmd = N'del "' + fn_escapecmdshellsymbolsremovequotes(@file_path) collate database_default + N'"'
  18438.         EXEC @retcode = master..xp_cmdshell @delfile_cmd, NO_OUTPUT
  18439.         if @@ERROR<>0
  18440.             goto FAILURE
  18441.         select @len=CHARINDEX ( '\' , reverse(@file_path) ) 
  18442.         select @file_path=SUBSTRING(@file_path , 1 , len(@file_path)-@len + 1)
  18443.         
  18444.         select @delfile_cmd = N'rmdir "' + fn_escapecmdshellsymbolsremovequotes(@file_path) collate database_default + N'"'
  18445.         EXEC @retcode = master..xp_cmdshell @delfile_cmd, NO_OUTPUT
  18446.         if @@ERROR<>0
  18447.             goto FAILURE
  18448.         fetch next from #per_script into @file_path
  18449.     end
  18450.     
  18451.     close #per_script
  18452.     deallocate #per_script
  18453.     return (0)
  18454. FAILURE:
  18455.     close #per_script
  18456.     deallocate #per_script
  18457.     return (1)
  18458. go
  18459. EXEC dbo.sp_MS_marksystemobject 'sp_MSremove_userscript'
  18460. go
  18461.  
  18462. dump tran master with no_log
  18463. go
  18464.  
  18465.  
  18466.  
  18467.  
  18468. checkpoint
  18469. go
  18470.  
  18471.  
  18472.  
  18473. use master
  18474. go
  18475.  
  18476. execute dbo.sp_configure 'update',1
  18477. go
  18478. reconfigure with override
  18479. go
  18480.  
  18481. set ANSI_NULLS off
  18482. go
  18483.  
  18484. dump tran master with no_log
  18485. go
  18486.  
  18487. /* 
  18488. ** Drop the stored procedures in this script using the old dropping SP 
  18489. ** and then drop itself
  18490. */
  18491. if exists (select * from sysobjects
  18492.     where type = 'P '
  18493.             and name = 'sp_MSdrop_rlrecon')
  18494. begin
  18495.     drop procedure sp_MSdrop_rlrecon
  18496. end
  18497.  
  18498. /*
  18499. ** Create stored procedures to drop the stored procedures
  18500. ** created by this script
  18501. */
  18502.  
  18503. raiserror('Creating procedure sp_MSdrop_rlrecon', 0,1)
  18504. GO
  18505. create procedure sp_MSdrop_rlrecon
  18506. as
  18507.  
  18508.     if exists (select * from sysobjects
  18509.     where type = 'P'
  18510.         and name = 'sp_MSaddinitialpublication')
  18511.     drop procedure sp_MSaddinitialpublication
  18512.  
  18513.     if exists (select * from sysobjects
  18514.     where type = 'P'
  18515.         and name = 'sp_MSaddinitialsubscription')
  18516.     drop procedure sp_MSaddinitialsubscription
  18517.  
  18518.     if exists (select * from sysobjects
  18519.         where type = 'P'
  18520.             and name = 'sp_MSdropconstraints')
  18521.     drop procedure sp_MSdropconstraints
  18522.  
  18523.     if exists (select * from sysobjects
  18524.             where type = 'P'
  18525.                 and name = 'sp_MSexclause')
  18526.         drop procedure sp_MSexclause
  18527.  
  18528.  
  18529.     if exists (select * from sysobjects
  18530.             where type = 'P'
  18531.                 and name = 'sp_MSgetcolordinalfromcolname')
  18532.         drop procedure sp_MSgetcolordinalfromcolname
  18533.         
  18534.     if exists (select * from sysobjects
  18535.             where type = 'P'
  18536.                 and name = 'sp_MSinsertbeforeimageclause')
  18537.         drop procedure sp_MSinsertbeforeimageclause
  18538.  
  18539.     if exists (select * from sysobjects
  18540.             where type = 'P'
  18541.                 and name = 'sp_MSmakectsview')
  18542.         drop procedure sp_MSmakectsview
  18543.  
  18544.     if exists (select * from sysobjects
  18545.                 where type = 'P' and
  18546.                 name = 'sp_MSmakeinsertproc')
  18547.         drop procedure sp_MSmakeinsertproc
  18548.         
  18549.     if exists (select * from sysobjects
  18550.                 where type = 'P' and
  18551.                 name = 'sp_MSmakeupdateproc')
  18552.         drop procedure sp_MSmakeupdateproc 
  18553.         
  18554.     if exists (select * from sysobjects
  18555.                 where type = 'P' and
  18556.                 name = 'sp_MScreatedupkeyupdatequery')
  18557.         drop procedure sp_MScreatedupkeyupdatequery 
  18558.         
  18559.     if exists (select * from sysobjects
  18560.                 where type = 'P' and
  18561.                 name = 'sp_MSmakeselectproc')
  18562.         drop procedure sp_MSmakeselectproc 
  18563.  
  18564.     if exists (select * from sysobjects
  18565.                 where type = 'P' and
  18566.                 name = 'sp_MSreplcheck_permission')
  18567.         drop procedure sp_MSreplcheck_permission 
  18568.  
  18569.     if exists (select * from sysobjects
  18570.     where type = 'P '
  18571.             and name = 'sp_MSinsertschemachange')
  18572.     drop procedure sp_MSinsertschemachange
  18573.  
  18574.     if exists (select * from sysobjects
  18575.     where type = 'P'
  18576.         and name = 'sp_MSaddinitialarticle')
  18577.     drop procedure sp_MSaddinitialarticle
  18578.  
  18579.     if exists (select * from sysobjects
  18580.     where type = 'P'
  18581.         and name = 'sp_MSaddinitialschemaarticle')
  18582.     drop procedure sp_MSaddinitialschemaarticle
  18583.         
  18584.     if exists (select * from sysobjects
  18585.                 where type = 'P' and
  18586.                 name = 'sp_MSinitdynamicsubscriber')
  18587.         drop procedure sp_MSinitdynamicsubscriber 
  18588.         
  18589.     if exists (select * from sysobjects
  18590.                 where type = 'P' and
  18591.                 name = 'sp_MSmakearticleprocs')
  18592.         drop procedure sp_MSmakearticleprocs
  18593.  
  18594.     if exists (select * from sysobjects
  18595.                 where type = 'P' and
  18596.                 name = 'sp_MSchecksnapshotstatus')
  18597.         drop procedure sp_MSchecksnapshotstatus
  18598.  
  18599.     if exists (select * from sysobjects
  18600.         where type = 'P'
  18601.             and name = 'sp_MSupdatesysmergearticles')
  18602.         drop procedure sp_MSupdatesysmergearticles        
  18603.  
  18604.     if exists (select * from sysobjects
  18605.         where type = 'P'
  18606.             and name = 'sp_MSdroparticletombstones')
  18607.         drop procedure sp_MSdroparticletombstones        
  18608.  
  18609.     if exists (select * from sysobjects
  18610.         where type = 'P'
  18611.             and name = 'sp_MSproxiedmetadata')
  18612.         drop procedure sp_MSproxiedmetadata        
  18613.     
  18614.     if exists (select * from sysobjects
  18615.                 where type = 'P' and
  18616.                 name = 'sp_MShelpmergearticles')
  18617.         drop procedure sp_MShelpmergearticles
  18618.  
  18619.     if exists (select * from sysobjects
  18620.                 where type = 'P' and
  18621.                 name = 'sp_MShelpmergeidentity')
  18622.         drop procedure sp_MShelpmergeidentity
  18623.  
  18624.     if exists (select * from sysobjects
  18625.                 where type = 'P' and
  18626.                 name = 'sp_MShelpmergeschemaarticles')
  18627.         drop procedure sp_MShelpmergeschemaarticles
  18628.  
  18629.     if exists (select * from sysobjects
  18630.                 where type = 'P' and
  18631.                 name = 'sp_MScheckidentityrange')
  18632.         drop procedure sp_MScheckidentityrange
  18633.  
  18634.     if exists (select * from sysobjects
  18635.                 where type = 'P' and
  18636.                 name = 'sp_MSfetchidentityrange')
  18637.         drop procedure sp_MSfetchidentityrange
  18638.  
  18639.     if exists (select * from sysobjects
  18640.                 where type = 'P' and
  18641.                 name = 'sp_MScreateretry')
  18642.         drop procedure sp_MScreateretry
  18643.  
  18644.     if exists (select * from sysobjects
  18645.                 where type = 'P' and
  18646.                 name = 'sp_MSdropretry')
  18647.         drop procedure sp_MSdropretry
  18648.  
  18649.     if exists (select * from sysobjects
  18650.                 where type = 'P' and
  18651.                 name = 'sp_MSdroptemptable')
  18652.         drop procedure sp_MSdroptemptable
  18653.  
  18654.     if exists (select * from sysobjects
  18655.                 where type = 'P' and
  18656.                 name = 'sp_MSenumretries')
  18657.         drop procedure sp_MSenumretries
  18658.  
  18659.     if exists (select * from sysobjects
  18660.                 where type = 'P' and
  18661.                 name = 'sp_MSdeleteretry')
  18662.         drop procedure sp_MSdeleteretry
  18663.  
  18664.     if exists (select * from sysobjects
  18665.                 where type = 'P' and
  18666.                 name = 'sp_MSgetonerow')
  18667.         drop procedure sp_MSgetonerow
  18668.  
  18669.     if exists (select * from sysobjects
  18670.                 where type = 'P' and
  18671.                 name = 'sp_MSchangearticleresolver')
  18672.            drop procedure sp_MSchangearticleresolver
  18673.  
  18674.     if exists (select * from sysobjects
  18675.                 where type = 'P' and
  18676.                 name = 'sp_MSgetlastrecgen')
  18677.         drop procedure sp_MSgetlastrecgen
  18678.  
  18679.     if exists (select * from sysobjects
  18680.                 where type = 'P' and
  18681.                 name = 'sp_MSgetlastsentgen')
  18682.         drop procedure sp_MSgetlastsentgen
  18683.  
  18684.     if exists (select * from sysobjects
  18685.                 where type = 'P' and
  18686.                 name = 'sp_MSgetlastsentrecgens')
  18687.         drop procedure sp_MSgetlastsentrecgens
  18688.  
  18689.     if exists (select * from sysobjects
  18690.                 where type = 'P' and
  18691.                 name = 'sp_MSsetlastrecgen')
  18692.         drop procedure sp_MSsetlastrecgen
  18693.  
  18694.     if exists (select * from sysobjects
  18695.                 where type = 'P' and
  18696.                 name = 'sp_MSbelongs')
  18697.         drop procedure sp_MSbelongs
  18698.  
  18699.     if exists (select * from sysobjects
  18700.                 where type = 'P' and
  18701.                 name = 'sp_MSsetupbelongs')
  18702.         drop procedure sp_MSsetupbelongs
  18703.  
  18704.     if exists (select * from sysobjects
  18705.                 where type = 'P' and
  18706.                 name = 'sp_MSsetupworktables')
  18707.         drop procedure sp_MSsetupworktables
  18708.         
  18709.     if exists (select * from sysobjects
  18710.                 where type = 'P' and
  18711.                 name = 'sp_MSsetupnotbelongs')
  18712.         drop procedure sp_MSsetupnotbelongs
  18713.  
  18714.     if exists (select * from sysobjects
  18715.                 where type = 'P' and
  18716.                 name = 'sp_MSsetupbelongs_withoutviewproc')
  18717.         drop procedure sp_MSsetupbelongs_withoutviewproc
  18718.         
  18719.     if exists (select * from sysobjects
  18720.                 where type = 'P' and
  18721.                 name = 'sp_MSexpandbelongs')
  18722.         drop procedure sp_MSexpandbelongs
  18723.  
  18724.     if exists (select * from sysobjects
  18725.                 where type = 'P' and
  18726.                 name = 'sp_MSexpandnotbelongs')
  18727.         drop procedure sp_MSexpandnotbelongs
  18728.  
  18729.     if exists (select * from sysobjects
  18730.                 where type = 'P' and
  18731.                 name = 'sp_MSenumpartialdeletes')
  18732.         drop procedure sp_MSenumpartialdeletes
  18733.  
  18734.     if exists (select * from sysobjects
  18735.                 where type = 'P' and
  18736.                 name = 'sp_MSsetlastsentgen')
  18737.         drop procedure sp_MSsetlastsentgen
  18738.  
  18739.     if exists (select * from sysobjects
  18740.                 where type = 'P' and
  18741.                 name = 'sp_MSdummyupdate')
  18742.         drop procedure sp_MSdummyupdate 
  18743.  
  18744.     if exists (select * from sysobjects
  18745.                 where type = 'P' and
  18746.                 name = 'sp_MSdeletepushagent')
  18747.         drop procedure sp_MSdeletepushagent
  18748.         
  18749.     if exists (select * from sysobjects
  18750.                 where type = 'P' and
  18751.                 name = 'sp_MSenumgenerations')
  18752.         drop procedure sp_MSenumgenerations
  18753.  
  18754.     if exists (select * from sysobjects
  18755.                 where type = 'P' and
  18756.                 name = 'sp_MScheckexistsgeneration')
  18757.         drop procedure sp_MScheckexistsgeneration
  18758.  
  18759.     if exists (select * from sysobjects
  18760.                 where type = 'P' and
  18761.                 name = 'sp_MSenumreplicas')
  18762.         drop procedure sp_MSenumreplicas
  18763.  
  18764.     if exists (select * from sysobjects
  18765.                 where type = 'P' and
  18766.                 name = 'sp_MSenumdeletesmetadata')
  18767.         drop procedure sp_MSenumdeletesmetadata
  18768.     
  18769.     if exists (select * from sysobjects
  18770.                 where type = 'P' and
  18771.                 name = 'sp_MSenumchanges')
  18772.         drop procedure sp_MSenumchanges
  18773.     
  18774.     if exists (select * from sysobjects
  18775.                 where type = 'P' and
  18776.                 name = 'sp_MSenumpartialchanges')
  18777.         drop procedure sp_MSenumpartialchanges
  18778.  
  18779.     if exists (select * from sysobjects
  18780.                 where type = 'P' and
  18781.                 name = 'sp_MSgetrowmetadata')
  18782.         drop procedure sp_MSgetrowmetadata
  18783.     if exists (select * from sysobjects
  18784.                 where type = 'P' and
  18785.                 name = 'sp_MSgetmetadatabatch')
  18786.         drop procedure sp_MSgetmetadatabatch
  18787.  
  18788.     if exists (select * from sysobjects
  18789.                 where type = 'P' and
  18790.                 name = 'sp_MSsetrowmetadata')
  18791.         drop procedure sp_MSsetrowmetadata
  18792.  
  18793.     if exists (select * from sysobjects
  18794.                 where type = 'P' and
  18795.                 name = 'sp_MSinsertgenhistory')
  18796.         drop procedure sp_MSinsertgenhistory
  18797.  
  18798.     if exists (select * from sysobjects
  18799.                 where type = 'P' and
  18800.                 name = 'sp_MSupdategenhistory')
  18801.         drop procedure sp_MSupdategenhistory
  18802.  
  18803.     if object_id('sp_MSlocalizeinterruptedgenerations') is not null
  18804.         drop procedure sp_MSlocalizeinterruptedgenerations
  18805.  
  18806.     if exists (select * from sysobjects
  18807.                 where type = 'P' and
  18808.                 name = 'sp_MSenumschemachange')
  18809.         drop procedure sp_MSenumschemachange
  18810.  
  18811.     if exists (select * from sysobjects
  18812.                 where type = 'P' and
  18813.                 name = 'sp_MSenumschemachange_70')
  18814.         drop procedure sp_MSenumschemachange_70
  18815.  
  18816.     if exists (select * from sysobjects
  18817.                 where type = 'P' and 
  18818.                 name = 'sp_MSenumschemachange_80')
  18819.         drop procedure sp_MSenumschemachange_80
  18820.  
  18821.     if exists (select * from sysobjects
  18822.                 where type = 'P' and 
  18823.                 name = 'sp_MSenumschemachange_80sp3')
  18824.         drop procedure sp_MSenumschemachange_80sp3
  18825.  
  18826.     if exists (select * from sysobjects
  18827.                 where type = 'P' and
  18828.                 name = 'sp_MSupdateschemachange')
  18829.         drop procedure sp_MSupdateschemachange
  18830.  
  18831.     if exists (select * from sysobjects
  18832.             where type = 'P'
  18833.                 and name = 'sp_MSadd_mergereplcommand')
  18834.         drop procedure sp_MSadd_mergereplcommand
  18835.  
  18836.     if exists (select * from sysobjects
  18837.             where type = 'P'
  18838.                 and name = 'sp_MSremove_mergereplcommand')
  18839.         drop procedure sp_MSremove_mergereplcommand
  18840.  
  18841.     if exists (select * from sysobjects
  18842.                 where type = 'P' and
  18843.                 name = 'sp_MSsetreplicainfo')
  18844.         drop procedure sp_MSsetreplicainfo
  18845.  
  18846.     if exists (select * from sysobjects
  18847.                 where type = 'P' and
  18848.                 name = 'sp_MSsetreplicastatus')
  18849.         drop procedure sp_MSsetreplicastatus
  18850.  
  18851.     if exists (select * from sysobjects
  18852.         where type = 'P'
  18853.             and name = 'sp_MScreateglobalreplica')
  18854.         drop procedure sp_MScreateglobalreplica
  18855.  
  18856.     if exists (select * from sysobjects
  18857.             where type = 'P'
  18858.                 and name = 'sp_MSsetconflictscript')
  18859.         drop procedure sp_MSsetconflictscript
  18860.  
  18861.     if exists (select * from sysobjects
  18862.             where type = 'P'
  18863.                 and name = 'sp_MSsetconflicttable')
  18864.         drop procedure sp_MSsetconflicttable
  18865.  
  18866.     if exists (select * from sysobjects
  18867.                 where type = 'P' and
  18868.                 name = 'sp_MSmakeconflictinsertproc')
  18869.         drop procedure sp_MSmakeconflictinsertproc
  18870.  
  18871.     if exists (select * from sysobjects
  18872.                 where type = 'P' and
  18873.                 name = 'sp_MSmaketempinsertproc')
  18874.         drop procedure sp_MSmaketempinsertproc
  18875.  
  18876.     if exists (select * from sysobjects
  18877.             where type = 'P'
  18878.                 and name = 'sp_MSgetconflictinsertproc')
  18879.         drop procedure sp_MSgetconflictinsertproc
  18880.  
  18881.     if exists (select * from sysobjects
  18882.                 where type = 'P' and
  18883.                 name = 'sp_MSinsertdeleteconflict')
  18884.         drop procedure sp_MSinsertdeleteconflict
  18885.  
  18886.     if exists (select * from sysobjects
  18887.                 where type = 'P' and
  18888.                 name = 'sp_MScheckmetadatamatch')
  18889.         drop procedure sp_MScheckmetadatamatch
  18890.  
  18891.     if exists (select * from sysobjects
  18892.                 where type = 'P' and
  18893.                 name = 'sp_MSdelrow')
  18894.         drop procedure sp_MSdelrow 
  18895.  
  18896.     if exists (select * from sysobjects
  18897.                 where type = 'P' and
  18898.                 name = 'sp_MSsetartprocs')
  18899.         drop procedure sp_MSsetartprocs
  18900.  
  18901.     if exists (select * from sysobjects
  18902.             where type = 'P'
  18903.                 and name = 'sp_MSmakesystableviews')
  18904.         drop procedure sp_MSmakesystableviews
  18905.  
  18906.     if exists (select * from sysobjects
  18907.             where type = 'P'
  18908.                 and name = 'sp_MSgetchangecount')
  18909.         drop procedure sp_MSgetchangecount
  18910.  
  18911.     if exists (select * from sysobjects
  18912.             where type = 'P'
  18913.                 and name = 'sp_MSuplineageversion')
  18914.         drop procedure sp_MSuplineageversion
  18915.  
  18916.     if exists (select * from sysobjects
  18917.             where type = 'P'
  18918.                 and name = 'sp_MSvalidatearticle')
  18919.         drop procedure sp_MSvalidatearticle
  18920.     if exists (select * from sysobjects
  18921.             where type = 'P'
  18922.                 and name = 'sp_MSgetviewcolumnlist')
  18923.         drop procedure sp_MSgetviewcolumnlist
  18924.     if exists (select * from sysobjects
  18925.             where type = 'P'
  18926.                 and name = 'sp_MSsubscriptionvalidated')
  18927.         drop procedure sp_MSsubscriptionvalidated
  18928.         
  18929.     if exists (select * from sysobjects
  18930.             where type = 'P'
  18931.                 and name = 'sp_MSdelsubrows')
  18932.         drop procedure sp_MSdelsubrows
  18933.         
  18934.     if exists (select * from sysobjects
  18935.             where type = 'P'
  18936.                 and name = 'sp_MSdelsubrowsbatch')
  18937.         drop procedure sp_MSdelsubrowsbatch
  18938.  
  18939.     if exists (select * from sysobjects
  18940.             where type = 'P'
  18941.                 and name = 'sp_MScontractsubsnb')
  18942.         drop procedure sp_MScontractsubsnb
  18943.  
  18944.     if exists (select * from sysobjects
  18945.             where type = 'P'
  18946.                 and name = 'sp_MSexpandsubsnb')
  18947.         drop procedure sp_MSexpandsubsnb
  18948.  
  18949.     if exists (select * from sysobjects
  18950.             where type = 'P'
  18951.                 and name = 'sp_MSmakeviewproc')
  18952.         drop procedure sp_MSmakeviewproc
  18953.  
  18954.     if exists (select * from sysobjects
  18955.             where type = 'P' and
  18956.                 name = 'sp_MScreatebeforetable')
  18957.         drop procedure sp_MScreatebeforetable 
  18958.  
  18959.     if exists (select * from sysobjects
  18960.             where type = 'P' and
  18961.                 name = 'sp_MShelpcreatebeforetable')
  18962.         drop procedure sp_MShelpcreatebeforetable 
  18963.  
  18964.     if exists (select * from sysobjects
  18965.             where type = 'P' and
  18966.                 name = 'sp_MShelpalterbeforetable')
  18967.         drop procedure sp_MShelpalterbeforetable 
  18968.  
  18969.     if exists (select * from sysobjects
  18970.             where type = 'P' and
  18971.                 name = 'sp_MSgetbeforetableinsert')
  18972.         drop procedure sp_MSgetbeforetableinsert 
  18973.  
  18974.     if exists (select * from sysobjects
  18975.             where type = 'P' and
  18976.                 name = 'sp_MSfixupbeforeimagetables')
  18977.         drop procedure sp_MSfixupbeforeimagetables 
  18978.  
  18979.     if exists (select * from sysobjects
  18980.             where type = 'P' and
  18981.                 name = 'sp_MSinserterrorlineage')
  18982.         drop procedure sp_MSinserterrorlineage 
  18983.  
  18984.     if exists (select * from sysobjects
  18985.                 where type = 'P' and
  18986.                 name = 'sp_MSevalsubscriberinfo')
  18987.         drop procedure sp_MSevalsubscriberinfo 
  18988.  
  18989.     if exists (select * from sysobjects
  18990.                 where type = 'P' and
  18991.                 name = 'sp_MSsetsubscriberinfo')
  18992.         drop procedure sp_MSsetsubscriberinfo 
  18993.  
  18994.     if exists (select * from sysobjects
  18995.                 where type = 'P' and
  18996.                 name = 'sp_MSgetsubscriberinfo')
  18997.         drop procedure sp_MSgetsubscriberinfo 
  18998.  
  18999.     if exists (select * from sysobjects
  19000.                 where type = 'P '
  19001.                 and name = 'sp_MSinsertgenerationschemachanges')
  19002.     drop procedure sp_MSinsertgenerationschemachanges
  19003.  
  19004.     if exists (select * from sysobjects
  19005.                 where type = 'P '
  19006.                 and name = 'sp_MSalreadyhavegeneration')
  19007.     drop procedure sp_MSalreadyhavegeneration
  19008.  
  19009.     if exists (select * from sysobjects
  19010.                 where type = 'P '
  19011.                 and name = 'sp_MSgettablecontents')
  19012.         drop procedure sp_MSgettablecontents
  19013.  
  19014.     if exists (select * from sysobjects
  19015.                 where type = 'P '
  19016.                 and name = 'sp_MSdelgenzero')
  19017.     drop procedure sp_MSdelgenzero
  19018.  
  19019.     if exists (select * from sysobjects
  19020.                 where type = 'P '
  19021.                 and name = 'sp_MSmakedynsnapshotvws')
  19022.     drop procedure sp_MSmakedynsnapshotvws
  19023.  
  19024.     if exists (select * from sysobjects
  19025.                 where type = 'P '
  19026.                 and name = 'sp_MSdropdynsnapshotvws')
  19027.     drop procedure sp_MSdropdynsnapshotvws
  19028.  
  19029.     if object_id('dbo.sp_MSscriptviewproc', 'P') is not null 
  19030.         drop procedure dbo.sp_MSscriptviewproc
  19031.  
  19032.     if object_id('dbo.sp_MSchunkgeneration', 'P') is not null 
  19033.         drop procedure dbo.sp_MSchunkgeneration
  19034.     
  19035. go
  19036. exec dbo.sp_MS_marksystemobject sp_MSdrop_rlrecon
  19037. go
  19038.  
  19039. EXEC dbo.sp_MSdrop_rlrecon
  19040. go
  19041.  
  19042.  
  19043.  
  19044. raiserror('Creating procedure sp_MSfetchidentityrange', 0,1)
  19045. GO
  19046.  
  19047. CREATE PROCEDURE sp_MSfetchidentityrange 
  19048. @tablename            sysname,
  19049. @adjust_only        bit
  19050. AS
  19051.  
  19052. declare @retcode             int
  19053. declare @objid                int
  19054. declare @distributor        sysname
  19055. declare @distribdb            sysname
  19056. declare @publisher            sysname
  19057. declare @publisher_db        sysname
  19058. declare @next_seed            bigint
  19059. declare @range                bigint
  19060. declare @threshold            int
  19061. declare @tablenick             int
  19062. declare @distproc            nvarchar(300)
  19063. declare @identity_support    int
  19064. select @publisher=@@SERVERNAME
  19065. select @publisher_db=db_name()
  19066.  
  19067. select @objid = object_id(@tablename)
  19068.  
  19069. select @identity_support=identity_support, @tablenick = nickname from sysmergearticles where objid=@objid
  19070.  
  19071. /*
  19072. ** do permission checking
  19073. */
  19074. exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick = @tablenick
  19075. if @retcode<>0 or @@ERROR<>0 return (1)
  19076.  
  19077.  
  19078. exec @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb   = @distribdb OUTPUT
  19079.         IF @@ERROR <> 0 or @retcode <> 0
  19080.             return (1)
  19081. SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSfetchAdjustidentityrange'
  19082. exec @retcode = @distproc @publisher=@publisher, 
  19083.                             @publisher_db=@publisher_db, 
  19084.                             @tablename=@tablename, 
  19085.                             @adjust_only=1, --do adjust only
  19086.                             @next_seed=@next_seed OUTPUT,
  19087.                             @range=@range OUTPUT,
  19088.                             @threshold=@threshold OUTPUT
  19089. IF @@ERROR <> 0 OR @retcode <> 0
  19090.     return (1)
  19091.  
  19092. --initialize article collection for agents.
  19093. if @adjust_only=0
  19094.     select @identity_support, @next_seed-range, range, threshold from MSrepl_identity_range where  objid = @objid
  19095. GO
  19096. exec dbo.sp_MS_marksystemobject sp_MSfetchidentityrange 
  19097. go
  19098. grant exec on dbo.sp_MSfetchidentityrange to public
  19099. go
  19100.  
  19101.  
  19102. raiserror('Creating procedure sp_MScheckidentityrange', 0,1)
  19103. GO
  19104.  
  19105. CREATE PROCEDURE sp_MScheckidentityrange 
  19106.     @pubid                 uniqueidentifier,
  19107.     @artname            sysname,
  19108.     @next_seed            bigint,
  19109.     @range                bigint,
  19110.     @threshold            int,
  19111.     @checkonly            int
  19112. AS
  19113.     declare @colid                int
  19114.     declare @colname            sysname
  19115.     declare @retcode            int
  19116.     declare @objid                int
  19117.     declare @identity_so_far    bigint
  19118.     declare @current_max        bigint
  19119.     declare @max_identity        bigint
  19120.     declare @tablename            sysname
  19121.     declare @flag                smallint
  19122.     declare @distributor        sysname
  19123.     declare @distribdb            sysname
  19124.     declare @republisher        bit
  19125.     declare @publisher            sysname
  19126.     declare @publisher_db        sysname
  19127.     declare @distproc            nvarchar(300)
  19128.     declare @pub_range            bigint
  19129.  
  19130.     /*
  19131.     ** Check to see if current publication has permission
  19132.     */
  19133.     if ({ fn ISPALUSER(@pubid)} <> 1)
  19134.     begin    
  19135.         RAISERROR (14126, 11, -1)
  19136.         return (1)
  19137.     end
  19138.     
  19139.     select @objid = objid from sysmergearticles where pubid=@pubid and name=@artname
  19140.     select @flag = 1
  19141.     select @republisher = 0
  19142.     select @tablename=object_name(@objid)
  19143.  
  19144.     if exists (select * from sysmergearticles where objid=@objid and pubid <>@pubid and pubid in (select pubid from 
  19145.                     sysmergepublications where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name()))
  19146.     begin
  19147.         select @publisher=@@SERVERNAME
  19148.         select @publisher_db=db_name()
  19149.         select @republisher = 1
  19150.         exec @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb   = @distribdb OUTPUT
  19151.         IF @@ERROR <> 0 or @retcode <> 0
  19152.         begin
  19153.             raiserror(14071, 16, -1)
  19154.             return (1)
  19155.             end
  19156.     end
  19157.  
  19158.     if @checkonly=1
  19159.     begin
  19160.         if @republisher=0
  19161.         begin
  19162.             --current_max is defaulted to max_identity value if not republished at subscribers.
  19163.             select @current_max = current_max from MSrepl_identity_range where objid=@objid
  19164.             select @identity_so_far = ident_current(@tablename)        
  19165.             if ident_incr(@tablename) < 0
  19166.                 select @flag = -1
  19167.             if @flag * 100 * (@identity_so_far - (@current_max + 1 - @range))/@range > @threshold
  19168.                 select 1 --needs bump up
  19169.             else
  19170.                 select 0 --no need to bump up
  19171.         end
  19172.         else
  19173.         begin
  19174.             select @current_max=0, @next_seed=0, @threshold=0, @range=0, @pub_range=0, @max_identity=0  --make them non-NULL
  19175.             SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MScheck_pub_identity'
  19176.             exec  @retcode=    @distproc @publisher=@@SERVERNAME,
  19177.                                       @publisher_db=@publisher_db,
  19178.                                       @tablename=@tablename,
  19179.                                       @range=@range OUTPUT,
  19180.                                       @max_identity=@max_identity OUTPUT,
  19181.                                       @next_seed = @next_seed OUTPUT,
  19182.                                       @pub_range=@pub_range OUTPUT
  19183.             if @retcode<>0 or @@ERROR<>0
  19184.             begin
  19185.                 raiserror(21195, 16, -1) 
  19186.                 return (1)
  19187.             end
  19188.             if (@max_identity-@next_seed)<@range or (@max_identity-@next_seed)<@pub_range
  19189.                 select 1
  19190.             else
  19191.                 select 0
  19192.         end
  19193.     end
  19194.     else
  19195.     begin
  19196.         if @republisher=0
  19197.         begin
  19198.             --its current_max value is to be set by sp_addmergearticle, if to be republished.
  19199.             update MSrepl_identity_range set max_identity=@next_seed + @range, next_seed=@next_seed, current_max=@next_seed + @range -1
  19200.                 where objid = @objid
  19201.             exec sp_MSreseed @objid, @next_seed, @range 
  19202.             if @@ERROR <> 0 
  19203.                 goto FAILURE
  19204.         end
  19205.         else
  19206.         begin
  19207.             SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSfetchAdjustidentityrange'
  19208.             exec @retcode = @distproc @publisher=@publisher, 
  19209.                             @publisher_db=@publisher_db, 
  19210.                             @tablename=@tablename, 
  19211.                             @for_publisher = 2,  --for repub case, increment max_identity at distributor side
  19212.                             @next_seed = @next_seed,
  19213.                             @range=@range OUTPUT,
  19214.                             @adjust_only=1 --do adjust only
  19215.             if @retcode<>0 or @@ERROR<>0
  19216.             begin
  19217.                 raiserror(21315, 16, -1, @tablename)
  19218.                 return (1)
  19219.             end
  19220.         end
  19221.     end
  19222.  
  19223.     return (0)
  19224. FAILURE:
  19225.     select 0
  19226.     return (1)
  19227. go
  19228. exec dbo.sp_MS_marksystemobject sp_MScheckidentityrange 
  19229. go
  19230. grant exec on dbo.sp_MScheckidentityrange to public
  19231. go
  19232.  
  19233. raiserror('Creating procedure sp_MShelpmergeidentity', 0,1)
  19234. GO
  19235.  
  19236. CREATE PROCEDURE sp_MShelpmergeidentity 
  19237.     @publication sysname
  19238. as
  19239.     declare @pubid                     uniqueidentifier
  19240.     declare @artid                     uniqueidentifier
  19241.     declare @nickname                int
  19242.     declare @next_seed                bigint
  19243.     declare @objid                    int
  19244.     declare @retcode                int
  19245.     declare @tablename                sysname
  19246.     declare @range                    bigint
  19247.     declare @threshold                int
  19248.     declare @distributor            sysname
  19249.     declare @distribdb                sysname
  19250.     declare @distproc                nvarchar(300)
  19251.     declare @db_name                sysname
  19252.     declare @tmp_table TABLE (tablename sysname, next_seed bigint, range bigint, threshold int, nickname int)
  19253.  
  19254.     /*
  19255.     ** To public.
  19256.     */
  19257.     set nocount on
  19258.     if (@publication is null)
  19259.         begin
  19260.         RAISERROR(14003, 16, -1)
  19261.         return (1)
  19262.         end
  19263.  
  19264.     EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb   = @distribdb OUTPUT
  19265.     IF @@ERROR <> 0 or @retcode <> 0
  19266.         return (1)
  19267.     
  19268.     select @db_name = db_name()
  19269.  
  19270.     select @pubid = pubid from sysmergepublications
  19271.         where name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=@db_name
  19272.  
  19273.     if (@pubid is null)
  19274.         begin
  19275.             RAISERROR (20026, 11, -1, @publication)
  19276.             return (1)
  19277.         end
  19278.  
  19279.     -- security check
  19280.     if ({ fn ISPALUSER(@pubid)} <> 1)
  19281.     begin    
  19282.         RAISERROR (14126, 11, -1)
  19283.         return (1)
  19284.     end
  19285.  
  19286.     
  19287.     select TOP 1 @artid=artid from sysmergearticles where pubid=@pubid and identity_support=1 order by nickname ASC
  19288.     while (@artid is not NULL)
  19289.     begin
  19290.         select @objid=objid, @nickname=nickname from sysmergearticles 
  19291.                 where pubid=@pubid and artid=@artid
  19292.         select @tablename=object_name(@objid)
  19293.         select @next_seed=0, @threshold=0, @range=0  --make them non-NULL
  19294.  
  19295.         SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MScheck_pub_identity'
  19296.         exec  @retcode=    @distproc @publisher=@@SERVERNAME,
  19297.                                       @publisher_db=@db_name,
  19298.                                       @tablename=@tablename,
  19299.                                       @range=@range OUTPUT,
  19300.                                       @threshold=@threshold OUTPUT,
  19301.                                       @next_seed = @next_seed OUTPUT
  19302.         if @retcode<>0 or @@ERROR<>0
  19303.             return (1)
  19304.         insert @tmp_table values(@tablename, @next_seed, @range, @threshold, @nickname)
  19305.         if @@ERROR<>0
  19306.         begin
  19307.             raiserror(21197, 16, -1)
  19308.             return (1)
  19309.         end
  19310.         select @artid = NULL 
  19311.         select TOP 1 @artid=artid from sysmergearticles 
  19312.             where pubid=@pubid and nickname>@nickname and identity_support=1 order by nickname ASC
  19313.     end
  19314.     select * from  @tmp_table order by nickname ASC
  19315.     
  19316.     return (0)    
  19317. go
  19318. exec dbo.sp_MS_marksystemobject sp_MShelpmergeidentity 
  19319. go
  19320. grant exec on dbo.sp_MShelpmergeidentity to public
  19321. go
  19322.  
  19323.  
  19324. raiserror('Creating procedure sp_MShelpmergearticles', 0,1)
  19325. GO
  19326.  
  19327. CREATE PROCEDURE sp_MShelpmergearticles 
  19328.     @publication sysname,
  19329.     @compatibility_level int = 7000000,
  19330.     @pubidin uniqueidentifier = NULL
  19331. as
  19332.     declare @pubid                     uniqueidentifier
  19333.     declare @artid                     uniqueidentifier
  19334.     declare @user_name                sysname
  19335.     declare @guid_col                sysname
  19336.     declare @identity_support         int
  19337.     declare @nickname                int
  19338.     declare @identity_so_far        bigint
  19339.     declare @next_seed                bigint
  19340.     declare @pub_range                bigint
  19341.     declare @objid                    int
  19342.     declare @qualname                nvarchar(270)
  19343.     declare @retcode                int
  19344.     declare @tablename                sysname
  19345.     declare @range                    bigint
  19346.     declare @current_max            bigint
  19347.     declare @threshold                int
  19348.     declare @distributor            sysname
  19349.     declare @distribdb                sysname
  19350.     declare @distproc                nvarchar(300)
  19351.     declare @flag                    smallint
  19352.     declare @c_max                    bigint
  19353.     declare @n_seed                    bigint
  19354.     declare @db_name                sysname
  19355.     declare @has_joins                int
  19356.     declare @article_filter_category int
  19357.     declare @haspartfilters            int
  19358.     declare @grouppartfilterarticles int
  19359.     declare @injoinfilters            int
  19360.     declare @nofilters                int
  19361.     declare @objid_looper            int
  19362.     declare @indexcol                int
  19363.     declare @rowcount1                int
  19364.     declare @rowcount2                int
  19365.  
  19366.     declare @tmp_table TABLE (tablename sysname, user_name sysname,  
  19367.             guid_col sysname NULL, next_seed bigint, range bigint, threshold int, artid uniqueidentifier, pubid uniqueidentifier, has_joins int, article_filter_category int, objid int, has_relation_with_joinarticles int default 0, node_visited bit default 0)
  19368.     declare @worktable TABLE (objid int NOT NULL, indexcol int)
  19369.  
  19370.     set @nofilters = 1
  19371.     set @haspartfilters = 2
  19372.     set @injoinfilters = 4
  19373.     set @grouppartfilterarticles = 8
  19374.     
  19375.     /*
  19376.     ** To public.
  19377.     */
  19378.     set nocount on
  19379.     if (@publication is null)
  19380.         begin
  19381.         RAISERROR(14003, 16, -1)
  19382.         return (1)
  19383.         end
  19384.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  19385.         begin
  19386.         RAISERROR(20054 , 16, -1)
  19387.         return (1)
  19388.         end
  19389.  
  19390.     EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb   = @distribdb OUTPUT
  19391.     IF @@ERROR <> 0 or @retcode <> 0
  19392.         return (1)
  19393.  
  19394.     
  19395.     select @db_name = db_name()
  19396.  
  19397.     if @pubidin is not NULL
  19398.         set @pubid = @pubidin
  19399.     else
  19400.         select @pubid = pubid from sysmergepublications
  19401.             where name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=@db_name
  19402.  
  19403.     if (@pubid is null)
  19404.         begin
  19405.         RAISERROR (20026, 11, -1, @publication)
  19406.         return (1)
  19407.         end
  19408.  
  19409.     /*
  19410.     ** Check to see if current publication has permission
  19411.     */
  19412.     if ({ fn ISPALUSER(@pubid) } <> 1)
  19413.     begin    
  19414.         RAISERROR (14126, 11, -1)
  19415.         return (1)
  19416.     end
  19417.  
  19418.  
  19419.     select TOP 1 @artid=artid from sysmergearticles where pubid=@pubid order by nickname ASC
  19420.     while (@artid is not NULL)
  19421.     begin
  19422.         select @objid=objid, @nickname=nickname, @identity_support=identity_support from sysmergearticles 
  19423.                 where pubid=@pubid and artid=@artid
  19424.         select @tablename=object_name(@objid)
  19425.         select @user_name=user_name(uid) from sysobjects where id=@objid
  19426.         select @qualname=QUOTENAME(@user_name) + '.' + QUOTENAME(@tablename)
  19427.         select @next_seed=NULL, @range=NULL, @threshold=NULL --null if not being updated later
  19428.         if @identity_support=1 and exists (select * from sysmergepublications where
  19429.             pubid = @pubid and  UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=@db_name)
  19430.         begin
  19431.             select @current_max=0, @next_seed=0, @threshold=0, @range=0, @pub_range=0  --make them non-NULL
  19432.             SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MScheck_pub_identity'
  19433.             exec  @retcode=    @distproc @publisher=@@SERVERNAME,
  19434.                                       @publisher_db=@db_name,
  19435.                                       @tablename=@tablename,
  19436.                                       @range=@range OUTPUT,
  19437.                                       @current_max=@current_max OUTPUT,
  19438.                                       @threshold=@threshold OUTPUT,
  19439.                                       @next_seed = @next_seed OUTPUT,
  19440.                                       @pub_range=@pub_range OUTPUT
  19441.             if @retcode<>0 or @@ERROR<>0
  19442.                 return (1)
  19443.  
  19444.             select @identity_so_far = IDENT_CURRENT(@tablename)
  19445.             select @flag=1
  19446.             if ident_incr(@tablename) < 0
  19447.                 select @flag = -1
  19448.  
  19449.             -- we attempted to adjust publisher side identity range based on its threshodl if needed
  19450.             -- however, non-dbo/sysadmin's will not be able to do so.
  19451.             -- so this is limited to dbos or sysadmins.
  19452.             if @flag * 100 * (@identity_so_far - (@current_max + 1 - @pub_range))/@pub_range > @threshold
  19453.                     and ((is_srvrolemember('sysadmin') = 1) or (is_member('db_owner') = 1)) 
  19454.             begin
  19455.                 select @c_max=@next_seed + @pub_range - 1
  19456.                 select @n_seed=@next_seed + @pub_range
  19457.                 SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSadjust_pub_identity'
  19458.                 exec  @retcode=@distproc @publisher=@@SERVERNAME,
  19459.                                         @publisher_db=@db_name,
  19460.                                         @tablename=@tablename,
  19461.                                         @current_max=@c_max,
  19462.                                         @next_seed = @n_seed
  19463.                 if @retcode<>0 or @@ERROR<>0
  19464.                     return (1)
  19465.  
  19466.                 exec @retcode=sp_MSreseed @objid, @next_seed, @pub_range, 1
  19467.                 if @@ERROR <> 0 or @retcode<>0
  19468.                 begin
  19469.                     raiserror(21197, 16, -1)
  19470.                     return (1)
  19471.                 end
  19472.                 select @next_seed=@next_seed + @pub_range
  19473.  
  19474.             end
  19475.         end
  19476.         else if @identity_support=1 and not exists (select * from sysmergepublications where
  19477.             pubid = @pubid and  UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=@db_name)
  19478.         begin
  19479.             /* This is the case of a message based subscriber acting like publisher */
  19480.             select @range = range, @threshold = threshold, @next_seed = next_seed
  19481.                 from MSrepl_identity_range where objid = @objid
  19482.         end
  19483.  
  19484.         if exists (select * from sysmergesubsetfilters where join_nickname = @nickname)
  19485.             set @has_joins = 1
  19486.         else 
  19487.             set @has_joins = 0
  19488.  
  19489.         -- reset for subsequent bitwise OR operations.
  19490.         set @article_filter_category = 0
  19491.  
  19492.         if exists (select * from sysmergesubsetfilters where pubid = @pubid and (join_nickname = @nickname or art_nickname = @nickname))
  19493.             set @article_filter_category = (@article_filter_category | @injoinfilters)
  19494.         
  19495.         if exists (select * from sysmergearticles where pubid = @pubid and nickname = @nickname and datalength(subset_filterclause) > 1)
  19496.             set @article_filter_category = (@article_filter_category | @haspartfilters | @grouppartfilterarticles)
  19497.         
  19498.         if (@article_filter_category = 0)
  19499.             set @article_filter_category = @nofilters
  19500.  
  19501.         select @guid_col=name from syscolumns where id=@objid and ColumnProperty(@objid, name, 'IsRowGuidCol')=1
  19502.         insert @tmp_table values(@tablename, @user_name, @guid_col, 
  19503.             @next_seed, @range, @threshold, @artid, @pubid, @has_joins, @article_filter_category, @objid, 0, 0)
  19504.         if @@ERROR<>0
  19505.         begin
  19506.             raiserror(21197, 16, -1)
  19507.             return (1)
  19508.         end
  19509.         select @artid = NULL 
  19510.         select TOP 1 @artid=artid from sysmergearticles 
  19511.             where pubid=@pubid and nickname>@nickname order by nickname ASC
  19512.     end
  19513.  
  19514.     -- Find articles that have no relations (in either direction - referring or referenced) with any articles in the join filter category.
  19515.  
  19516.     if exists (select * from @tmp_table where (article_filter_category & @injoinfilters) = @injoinfilters)
  19517.     begin
  19518.  
  19519.         --create unique index #uncworktable on @worktable(objid, indexcol)
  19520.         update @tmp_table set node_visited = 1 
  19521.         where objid not in (select fkeyid from sysreferences)
  19522.         and objid not in (select rkeyid from sysreferences)
  19523.         and (article_filter_category & @injoinfilters) = 0
  19524.  
  19525.         -- get the min objid from the temp table of all articles
  19526.         select @objid_looper = min(objid) from @tmp_table where node_visited = 0
  19527.         
  19528.         while (@objid_looper is not null)
  19529.         begin
  19530.             delete from @worktable
  19531.  
  19532.             select @indexcol = 0
  19533.  
  19534.             insert into @worktable values (@objid_looper, @indexcol)
  19535.                         
  19536.             -- find all the objects referenced by this object and all objects that reference this object.
  19537.             insert into @worktable select distinct rkeyid, @indexcol+1 from sysreferences where fkeyid = @objid_looper
  19538.                                             and rkeyid not in (select objid from @worktable)
  19539.             select @rowcount1 = @@rowcount
  19540.             
  19541.             insert into @worktable select distinct fkeyid, @indexcol+1 from sysreferences where rkeyid = @objid_looper
  19542.                                             and fkeyid not in (select objid from @worktable)
  19543.             select @rowcount2 = @@rowcount
  19544.             
  19545.             while (@rowcount1 <> 0 or @rowcount2 <> 0)
  19546.             begin
  19547.                 
  19548.                 select @indexcol = @indexcol+1
  19549.  
  19550.                 insert into @worktable select distinct s.rkeyid, @indexcol+1 from sysreferences s, @worktable w, @tmp_table t where s.fkeyid = w.objid and w.objid = t.objid
  19551.                                             and w.indexcol = @indexcol and t.node_visited = 0 and s.rkeyid not in (select objid from @worktable)
  19552.                 select @rowcount1 = @@rowcount
  19553.                 
  19554.                 insert into @worktable select distinct s.fkeyid, @indexcol+1 from sysreferences s, @worktable w, @tmp_table t where s.rkeyid = w.objid and w.objid = t.objid
  19555.                                             and w.indexcol = @indexcol and t.node_visited = 0 and s.fkeyid not in (select objid from @worktable)
  19556.                 select @rowcount2 = @@rowcount
  19557.             end
  19558.  
  19559.             if exists (select * from @worktable w, @tmp_table t where w.objid = t.objid and (t.article_filter_category & @injoinfilters) = @injoinfilters)
  19560.             begin
  19561.                 -- all articles in @worktable have a direct or indirect relation with at least one object in the join articles category.
  19562.                 update @tmp_table set node_visited = 1, has_relation_with_joinarticles = 1 
  19563.                 from @tmp_table t, @worktable w 
  19564.                 where w.objid = t.objid 
  19565.             end
  19566.             else
  19567.             begin
  19568.                 -- none of the articles in @worktable has any relation (direct or indirect) with any article in the join articles category.            
  19569.                 update @tmp_table set node_visited = 1, has_relation_with_joinarticles = 0 
  19570.                 from @tmp_table t, @worktable w 
  19571.                 where w.objid = t.objid 
  19572.             end
  19573.  
  19574.             -- process more unvisited articles from @tmp_table
  19575.             select @objid_looper = min(objid) from @tmp_table where objid > @objid_looper and node_visited = 0
  19576.         end
  19577.     end
  19578.     
  19579.     /* If the 7.0 merge agent is making this call then we need to make sure that the CLSID of the sp resolver is the old one and not the new one */
  19580.     if @compatibility_level = 7000000
  19581.         begin
  19582.             begin transaction 
  19583.                 update sysmergearticles set resolver_clsid = '{6F31CE30-7BE4-11d1-9B0A-00C04FC2DEB3}' where article_resolver = 'Microsoft SQLServer Stored Procedure Resolver'
  19584.                 select name, t.tablename, t.user_name, a.artid, pre_creation_command, a.pubid, nickname,
  19585.                     column_tracking, status, resolver_clsid, conflict_script, conflict_table,
  19586.                     insert_proc, update_proc, select_proc, destination_object, missing_col_count, 
  19587.                     missing_cols, t.guid_col, 
  19588.                     article_resolver, resolver_info, subset_filterclause, has_joins, excluded_col_count, 
  19589.                     excluded_cols, destination_owner, identity_support, t.next_seed, t.range, t.threshold, 
  19590.                     verify_resolver_signature, allow_interactive_resolver, fast_multicol_updateproc, check_permissions, 
  19591.                     t.article_filter_category, t.has_relation_with_joinarticles, published_in_tran_pub
  19592.                 from sysmergearticles a, @tmp_table t
  19593.                 where a.artid=t.artid and a.pubid=t.pubid order by a.nickname
  19594.             rollback transaction                
  19595.         end
  19596.     else
  19597.         begin
  19598.             select name, t.tablename, t.user_name, a.artid, pre_creation_command, a.pubid, nickname,
  19599.                 column_tracking, status, resolver_clsid, conflict_script, conflict_table,
  19600.                 insert_proc, update_proc, select_proc, destination_object, missing_col_count, 
  19601.                 missing_cols, t.guid_col, 
  19602.                 article_resolver, resolver_info, subset_filterclause, has_joins, excluded_col_count, 
  19603.                 excluded_cols, destination_owner, identity_support, t.next_seed, t.range, t.threshold, 
  19604.                 verify_resolver_signature, allow_interactive_resolver, fast_multicol_updateproc, check_permissions, 
  19605.                 t.article_filter_category, t.has_relation_with_joinarticles, published_in_tran_pub
  19606.             from sysmergearticles a, @tmp_table t
  19607.             where a.artid=t.artid and a.pubid=t.pubid order by a.nickname
  19608.         end            
  19609.  
  19610.     return (0)    
  19611. go
  19612. exec dbo.sp_MS_marksystemobject sp_MShelpmergearticles 
  19613. go
  19614. grant exec on dbo.sp_MShelpmergearticles to public
  19615. go
  19616.  
  19617. raiserror('Creating procedure sp_MShelpmergeschemaarticles', 0,1)
  19618. go
  19619.  
  19620. CREATE PROCEDURE sp_MShelpmergeschemaarticles
  19621.     @publication sysname
  19622. as
  19623. begin
  19624.     set nocount on
  19625.  
  19626.     declare @pubid         uniqueidentifier
  19627.     declare @db_name       sysname
  19628.  
  19629.     if (@publication is null)
  19630.     begin
  19631.         raiserror(14003, 16, -1)
  19632.         return (1)
  19633.     end
  19634.  
  19635.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  19636.     begin
  19637.         raiserror(20054, 16, -1)
  19638.         return (1)
  19639.     end
  19640.     
  19641.     select @db_name = db_name()
  19642.     select @pubid = pubid from dbo.sysmergepublications
  19643.         where name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db = @db_name
  19644.  
  19645.     if (@pubid is null)
  19646.     begin
  19647.         raiserror(20026, 11, -1, @publication)
  19648.         return (1)
  19649.     end
  19650.  
  19651.     /*
  19652.     ** Check to see if current publication has permission
  19653.     */
  19654.     if ({ fn ISPALUSER(@pubid) } <> 1)
  19655.     begin    
  19656.         RAISERROR (14126, 11, -1)
  19657.         return (1)
  19658.     end
  19659.  
  19660.     select a.name, o.name, user_name(o.uid), a.destination_object, a.destination_owner, a.artid, @pubid, a.pre_creation_command, a.status, a.type 
  19661.       from dbo.sysmergeschemaarticles a
  19662.     inner join sysobjects o
  19663.         on a.objid = o.id 
  19664.         where pubid = @pubid 
  19665.  
  19666.     return 0
  19667. end
  19668. go
  19669. exec dbo.sp_MS_marksystemobject sp_MShelpmergeschemaarticles 
  19670. go
  19671. grant exec on dbo.sp_MShelpmergeschemaarticles to public
  19672. go
  19673.  
  19674.  
  19675. raiserror('Creating procedure sp_MScreateretry', 0,1)
  19676. GO
  19677.  
  19678. CREATE PROCEDURE sp_MScreateretry 
  19679. as
  19680.     declare @tname sysname
  19681.     declare @pname sysname
  19682.     declare @tempname sysname
  19683.     declare @guid uniqueidentifier
  19684.     declare @guidstr varchar(40)
  19685.     declare @retcode smallint
  19686.  
  19687.     /*
  19688.     ** Check to see if current publication has permission
  19689.     */
  19690.     if not exists (select * from dbo.sysmergepublications 
  19691.                             where 1 = {fn ISPALUSER(pubid)})
  19692.     begin    
  19693.         RAISERROR (14126, 11, -1)
  19694.         return (1)
  19695.     end
  19696.  
  19697.     set @guid = newid()
  19698.     exec @retcode=sp_MSguidtostr @guid, @guidstr out
  19699.     if @retcode<>0 or @@ERROR<>0 return (1)
  19700.     set @tempname = '##retry_' + @guidstr
  19701.  
  19702.     exec @retcode = dbo.sp_MSuniquetempname @tempname, @tempname out
  19703.     if (@@error <> 0) OR @retcode <> 0
  19704.         begin
  19705.         RAISERROR(15001, 16, -1, 'sp_MSuniquetempname')
  19706.         return (1)
  19707.         end
  19708.  
  19709.     exec ('create table ' + @tempname + ' (tablenick int NOT NULL, rowguid uniqueidentifier ROWGUIDCOL default newid() not null, errcode int NOT NULL, errtext nvarchar(255) NULL, type tinyint NOT NULL)' )
  19710.  
  19711.     if (@@error <> 0)
  19712.         begin
  19713.         RAISERROR(15001, 16, -1, @tempname)
  19714.         return (1)
  19715.         end
  19716.  
  19717.     set     @tname = @tempname
  19718.     set @tempname = '##insert_' + @guidstr
  19719.  
  19720.     exec @retcode = dbo.sp_MSuniquetempname @tempname, @tempname out
  19721.     if (@@error <> 0)
  19722.         begin
  19723.         RAISERROR(15001, 16, -1, 'sp_MSuniquetempname')
  19724.         return (1)
  19725.         end
  19726.  
  19727.     exec @retcode = dbo.sp_MSmaketempinsertproc @tname, @tempname
  19728.     if  @@ERROR <>0 or @retcode<>0 return (1)
  19729.  
  19730.     select @pname = @tempname
  19731.     select @tname, @pname
  19732.     return (0)    
  19733. go
  19734. exec dbo.sp_MS_marksystemobject sp_MScreateretry 
  19735. go
  19736. grant exec on dbo.sp_MScreateretry to public
  19737.  
  19738. raiserror('Creating procedure sp_MSdropretry', 0,1)
  19739. GO
  19740.  
  19741. CREATE PROCEDURE sp_MSdropretry (@tname sysname, @pname sysname)
  19742. as
  19743.     declare @retcode int
  19744.     declare @quotedtname sysname
  19745.     declare @quotedpname sysname
  19746.     
  19747.     /*
  19748.     ** To public
  19749.     */
  19750.     if not exists (select * from dbo.sysmergepublications 
  19751.                             where 1 = {fn ISPALUSER(pubid)})
  19752.     begin    
  19753.         RAISERROR (14126, 11, -1)
  19754.         return (1)
  19755.     end
  19756.  
  19757.     select @quotedtname = quotename(@tname)
  19758.     select @quotedpname = quotename(@pname)
  19759.     
  19760.     exec ('drop table ' + @quotedtname)
  19761.     if @@ERROR <> 0 return(1)
  19762.     exec ('drop procedure ' + @quotedpname)
  19763.     if @@ERROR <> 0 return(1)
  19764.     return (0)    
  19765. go
  19766. exec dbo.sp_MS_marksystemobject sp_MSdropretry 
  19767. go
  19768. grant exec on dbo.sp_MSdropretry to public
  19769. go
  19770.  
  19771. raiserror('Creating procedure sp_MSdroptemptable', 0,1)
  19772. GO
  19773. CREATE PROCEDURE sp_MSdroptemptable (@tname sysname)
  19774. as
  19775.     declare @quotedtname sysname
  19776.     
  19777.     select @quotedtname = quotename(@tname)
  19778.     
  19779.     exec ('if OBJECT_ID(''tempdb..' + @quotedtname + ''') is not NULL drop table ' + @quotedtname)
  19780.     
  19781.     if @@ERROR <> 0 
  19782.         return(1)
  19783.     
  19784.     return (0)    
  19785. go
  19786. exec dbo.sp_MS_marksystemobject sp_MSdroptemptable 
  19787. go
  19788. grant exec on dbo.sp_MSdroptemptable to public
  19789. go
  19790.  
  19791. raiserror('Creating procedure sp_MSchangearticleresolver', 0,1)
  19792. GO
  19793.  
  19794. CREATE PROCEDURE sp_MSchangearticleresolver (
  19795. @article_resolver         nvarchar(255),
  19796. @resolver_clsid            nvarchar(40),
  19797. @artid                    uniqueidentifier,
  19798. @resolver_info            sysname = NULL
  19799. )
  19800. as
  19801.     if (@resolver_clsid='') select @resolver_clsid = NULL
  19802.     UPDATE sysmergearticles
  19803.         SET article_resolver = @article_resolver, resolver_clsid = @resolver_clsid, resolver_info = @resolver_info
  19804.         WHERE artid = @artid
  19805.     if @@ERROR <> 0 
  19806.           RETURN (1)
  19807.     return (0)     
  19808. go
  19809.  
  19810. exec dbo.sp_MS_marksystemobject sp_MSchangearticleresolver
  19811. go
  19812.  
  19813. -- ****************************************************
  19814. -- THIS COMMENTED CODE SECTION WILL BE DELETED SOON
  19815. -- sp_MSgetversion is now part of XPSTAR.DLL and 
  19816. -- will not be installed by REPL code
  19817.  
  19818. --raiserror('Creating sp_MSgetversion', 0,1)
  19819. --GO
  19820. if not exists (select * from sysobjects where name = 'sp_MSgetversion')
  19821. begin
  19822.     exec dbo.sp_addextendedproc 'sp_MSgetversion', 'xpstar.dll'
  19823.     exec dbo.sp_MS_marksystemobject sp_MSgetversion
  19824.     grant exec on dbo.sp_MSgetversion to public
  19825. end
  19826. go
  19827. -- ****************************************************
  19828.  
  19829. raiserror('Creating procedure sp_MSenumretries', 0,1)
  19830. GO
  19831.  
  19832. CREATE PROCEDURE sp_MSenumretries
  19833.     (@tname nvarchar(386),
  19834.      @maxrows int,
  19835.      @tablenick int,
  19836.      @rowguid uniqueidentifier)
  19837. as
  19838.     declare @tnstring nvarchar(12)
  19839.     declare @rgstring nvarchar(38)
  19840.     declare @retcode int
  19841.     declare @quotedtname nvarchar(388)
  19842.  
  19843.     /*
  19844.     ** Modify temp table, granted to public.
  19845.     */
  19846.  
  19847.     declare @selecttop nvarchar(20)
  19848.  
  19849.     select @quotedtname = quotename(@tname)
  19850.     
  19851.     if (@maxrows = 0)
  19852.         set @selecttop= 'select'
  19853.     else
  19854.         set @selecttop= 'select top ' + cast(@maxrows as nvarchar(9)) 
  19855.     
  19856.     if (@tablenick < 1)
  19857.     begin
  19858.         execute (@selecttop + ' tablenick, rowguidcol, errcode, errtext, type from ' + @quotedtname + 
  19859.                  ' order by tablenick, rowguidcol')
  19860.         IF @@ERROR <>0 RETURN (1)          
  19861.     end
  19862.     else
  19863.     begin
  19864.         set @tnstring = convert(nchar, @tablenick)
  19865.         set @rgstring = '''' + convert(nchar(36), @rowguid) + ''''
  19866.         execute (@selecttop + ' tablenick, rowguidcol, errcode, errtext, type from ' + @quotedtname + 
  19867.                 ' where (tablenick = ' + @tnstring + ' and  rowguidcol > ' + @rgstring + ') or
  19868.                      tablenick > ' + @tnstring + ' order by tablenick, rowguidcol' )
  19869.         if @@ERROR <> 0 RETURN (1)
  19870.     end
  19871.     return (0)    
  19872. go
  19873. exec dbo.sp_MS_marksystemobject sp_MSenumretries
  19874. go
  19875. grant exec on dbo.sp_MSenumretries to public
  19876.  
  19877. raiserror('Creating procedure sp_MSdeleteretry', 0,1)
  19878. GO
  19879.  
  19880. CREATE PROCEDURE sp_MSdeleteretry 
  19881.     (@temptable nvarchar(386),
  19882.      @tablenick int,
  19883.      @rowguid uniqueidentifier)
  19884. as
  19885.     declare @guidstr nvarchar(38)
  19886.     declare @nickstr nvarchar(12)
  19887.     declare @retcode int
  19888.     declare @quotedtemptable nvarchar(388)
  19889.     
  19890.     /*
  19891.     ** do permission checking
  19892.     */
  19893.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick = @tablenick
  19894.     if @retcode<>0 or @@ERROR<>0 return (1)
  19895.     
  19896.     set @nickstr = convert(nchar, @tablenick)
  19897.     set @guidstr = '''' + convert(nchar(36), @rowguid) + ''''
  19898.     
  19899.     select @quotedtemptable = quotename(@temptable)
  19900.     execute ('delete from ' + @quotedtemptable + ' where tablenick = ' +
  19901.               @nickstr + ' and rowguidcol = ' + @guidstr)
  19902.     IF @@ERROR <>0 RETURN (1)
  19903.     return (0)
  19904. go
  19905. exec dbo.sp_MS_marksystemobject sp_MSdeleteretry 
  19906. go
  19907. grant exec on dbo.sp_MSdeleteretry to public
  19908. go
  19909.  
  19910. raiserror('Creating procedure sp_MSdeletepushagent', 0,1)
  19911. GO
  19912.  
  19913. /*
  19914. ** This procedure is obselete for dropping push agent at distribution database.
  19915. ** If we were to recover, don't use server id as parameter for RPC into distributor.
  19916. ** Use server name instead.
  19917. */
  19918. CREATE PROCEDURE sp_MSdeletepushagent (
  19919.     @publisher             sysname,
  19920.     @publisher_db         sysname,
  19921.     @publication         sysname,
  19922.     @subscriber             sysname,
  19923.     @subscriber_db         sysname
  19924.     ) AS
  19925.  
  19926. declare @distributor     sysname
  19927. declare @distribdb        sysname
  19928. declare @pubid            uniqueidentifier
  19929. declare @distproc        nvarchar(300)
  19930. declare @pub_srvid        smallint
  19931. declare @sub_srvid        smallint
  19932. declare @retcode        smallint
  19933.  
  19934. /*
  19935. ** Do permission checking
  19936. */
  19937. exec @retcode=sp_MSreplcheck_publish
  19938. if @retcode<>0 or @@ERROR<>0 return (1)
  19939.  
  19940.  
  19941. EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb   = @distribdb OUTPUT
  19942.         IF @@ERROR <> 0 or @retcode <> 0
  19943.             return (1)
  19944.         
  19945. select @pub_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
  19946. select @sub_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
  19947. select @pubid=pubid from sysmergepublications where name=@publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
  19948.  
  19949. SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSdrop_agent_entry'
  19950.  
  19951. EXEC @retcode = @distproc @pub_srvid, @publisher_db, @publication, @sub_srvid, @subscriber_db
  19952.         IF @@ERROR <> 0 OR @retcode <> 0
  19953.             return (1)
  19954. return (0)
  19955. GO
  19956. exec dbo.sp_MS_marksystemobject sp_MSdeletepushagent
  19957. go
  19958. grant exec on dbo.sp_MSdeletepushagent to public
  19959. go
  19960.  
  19961. raiserror('Creating procedure sp_MSgetonerow', 0,1)
  19962. GO
  19963.  
  19964. CREATE PROCEDURE sp_MSgetonerow
  19965.     (@tablenick int,
  19966.      @rowguid uniqueidentifier,
  19967.      @pubid uniqueidentifier = NULL)
  19968. as
  19969.     declare @retcode     smallint
  19970.     declare @procname    sysname
  19971.  
  19972.     /*
  19973.     ** Check to see if current publication has permission
  19974.     */
  19975.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick = @tablenick, @pubid = @pubid
  19976.     if @retcode<>0 or @@ERROR<>0 return (1)
  19977.     
  19978.     select @procname = select_proc from sysmergearticles where nickname = @tablenick and pubid=@pubid
  19979.     
  19980.     exec @retcode = @procname @type =1, @rowguid=@rowguid
  19981.     IF @@ERROR<>0 or @retcode<>0 RETURN (1)
  19982.     return (0)
  19983. go
  19984. exec dbo.sp_MS_marksystemobject sp_MSgetonerow
  19985. go
  19986. grant exec on dbo.sp_MSgetonerow to public
  19987. go
  19988.  
  19989. raiserror('Creating procedure sp_MSuplineageversion', 0,1)
  19990. GO
  19991.  
  19992. CREATE PROCEDURE sp_MSuplineageversion
  19993.     (@tablenick int,
  19994.      @rowguid uniqueidentifier,
  19995.      @version int)
  19996. as
  19997.     declare @replnick int
  19998.     declare @curversion int
  19999.     declare @lineage varbinary(255)
  20000.     declare @retcode int
  20001.     declare @colv varbinary(2048)
  20002.     declare @col_tracking int
  20003.     declare @rowintombstone int
  20004.     
  20005.     /*
  20006.     ** Check to see if current publication has permission
  20007.     */
  20008.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick = @tablenick
  20009.     if @retcode<>0 or @@ERROR<>0 return (1)
  20010.     
  20011.     exec dbo.sp_MSgetreplnick @nickname = @replnick out
  20012.     if (@@error <> 0) or @replnick IS NULL 
  20013.         begin
  20014.         RAISERROR (14055, 11, -1)
  20015.         RETURN(1)
  20016.         end                 
  20017.     if (@rowguid is null)
  20018.         begin
  20019.         RAISERROR(14043, 16, -1, '@rowguid')
  20020.         return (1)
  20021.         end
  20022.     if (@tablenick is null)
  20023.         begin
  20024.         RAISERROR(14043, 16, -1, '@tablenick')
  20025.         return (1)
  20026.         end
  20027.  
  20028.     select @col_tracking = column_tracking
  20029.              from sysmergearticles where nickname = @tablenick
  20030.  
  20031.     begin transaction
  20032.     save tran sp_MSuplineageversion
  20033.  
  20034.     -- get lineage, locking row in MSmerge_contents. If not found there, also try MSmerge_tombstone
  20035.     set @rowintombstone= 0
  20036.     select @lineage = lineage, @colv = colv1 from dbo.MSmerge_contents (UPDLOCK ROWLOCK index = 1) where tablenick = @tablenick and
  20037.             rowguid = @rowguid
  20038.     if (@lineage is null)
  20039.     begin
  20040.         select @lineage = lineage from dbo.MSmerge_tombstone (UPDLOCK ROWLOCK index = 1) where tablenick = @tablenick and
  20041.             rowguid = @rowguid
  20042.         set @colv= NULL
  20043.         set @rowintombstone= 1
  20044.     end
  20045.     if (@lineage is null)
  20046.     begin
  20047.         RAISERROR(14043, 16, -1, '@lineage')
  20048.         goto Failure
  20049.     end
  20050.  
  20051.     set @curversion = 0
  20052.     while (@curversion < @version)
  20053.     begin
  20054.         set @lineage= { fn UPDATELINEAGE(@lineage, @replnick, 1) }
  20055.         set @curversion= { fn GETMAXVERSION(@lineage) }
  20056.         IF @@ERROR<>0 goto Failure
  20057.     end
  20058.     if (@col_tracking = 0 or @colv is NULL)
  20059.         set @colv = NULL
  20060.     else
  20061.         set @colv = { fn UPDATECOLVBM(@colv, @replnick, 0x01, 0x00, @curversion) }
  20062.         
  20063.     -- update lineage in MSmerge_contents or MSmerge_tombstone
  20064.     if (@rowintombstone = 0)
  20065.     begin
  20066.         update dbo.MSmerge_contents set lineage = @lineage, colv1 = @colv where 
  20067.             tablenick = @tablenick and rowguid = @rowguid
  20068.     end
  20069.     else
  20070.     begin
  20071.         update dbo.MSmerge_tombstone set lineage = @lineage where
  20072.             tablenick = @tablenick and rowguid = @rowguid
  20073.     end
  20074.  
  20075.     commit
  20076.     return (0)
  20077. Failure:
  20078.     rollback tran sp_MSuplineageversion
  20079.     commit tran
  20080.     return(1)
  20081. go
  20082. exec dbo.sp_MS_marksystemobject sp_MSuplineageversion
  20083. go
  20084. grant exec on dbo.sp_MSuplineageversion to public
  20085.  
  20086. raiserror('Creating procedure sp_MSgetlastrecgen', 0,1)
  20087. GO
  20088.  
  20089. CREATE PROCEDURE sp_MSgetlastrecgen
  20090.     (@repid uniqueidentifier)
  20091. as
  20092.     declare @pubid         uniqueidentifier
  20093.     declare @pubname     sysname
  20094.     declare @status     int
  20095.     declare @retcode    int
  20096.  
  20097.     /*
  20098.     ** do permission checking
  20099.     */
  20100.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @repid = @repid
  20101.     if @retcode<>0 or @@ERROR<>0 return (1)
  20102.  
  20103.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  20104.         begin
  20105.         RAISERROR(20054 , 16, -1)
  20106.         return (1)
  20107.         end
  20108.  
  20109.     if (@repid is null)
  20110.         begin
  20111.             RAISERROR(14043, 16, -1, '@repid')
  20112.             return (1)
  20113.         end
  20114.  
  20115.    /*
  20116.     ** Check the publication status at the publisher - if it is inactive ( say because of a 
  20117.     ** metadata cleanup event then return an error so the current merge will quit.
  20118.     */
  20119.     select @pubid = pubid from sysmergesubscriptions where subid = @repid
  20120.     if (@pubid is not null)
  20121.         begin
  20122.             EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
  20123.             IF @retcode = 0
  20124.                 BEGIN
  20125.  
  20126.                     select @pubname = name, @status = status from sysmergepublications where pubid = @pubid
  20127.                     if @status = 0
  20128.                         begin
  20129.                             RAISERROR(21505, 16, -1, @pubname)
  20130.                             return (1)
  20131.                         end
  20132.                 END
  20133.         end
  20134.  
  20135.     select recgen, recguid from MSmerge_replinfo where repid = @repid
  20136.     return (0)
  20137. go
  20138. exec dbo.sp_MS_marksystemobject sp_MSgetlastrecgen
  20139. go
  20140. grant exec on dbo.sp_MSgetlastrecgen to public
  20141.  
  20142. raiserror('Creating procedure sp_MSgetlastsentgen', 0,1)
  20143. GO
  20144.  
  20145. CREATE PROCEDURE sp_MSgetlastsentgen
  20146.     (@repid uniqueidentifier)
  20147. as
  20148.     declare @pubid         uniqueidentifier
  20149.     declare @pubname     sysname
  20150.     declare @status     int
  20151.     declare @retcode    int
  20152.  
  20153.     /*
  20154.     ** do permission checking
  20155.     */
  20156.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @repid = @repid
  20157.     if @retcode<>0 or @@ERROR<>0 return (1)
  20158.  
  20159.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  20160.         begin
  20161.         RAISERROR(20054 , 16, -1)
  20162.         return (1)
  20163.         end
  20164.  
  20165.     if (@repid is null)
  20166.         begin
  20167.             RAISERROR(14043, 16, -1, '@repid')
  20168.             return (1)
  20169.         end
  20170.     
  20171.     /*
  20172.     ** Check the publication status at the publisher - if it is inactive ( say because of a 
  20173.     ** metadata cleanup event then return an error so the current merge will quit.
  20174.     */
  20175.     select @pubid = pubid from sysmergesubscriptions where subid = @repid
  20176.     if (@pubid is not null)
  20177.         begin
  20178.             EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
  20179.             IF @retcode = 0
  20180.                 BEGIN
  20181.  
  20182.                     select @pubname = name, @status = status from sysmergepublications where pubid = @pubid
  20183.                     if @status = 0
  20184.                         begin
  20185.                             RAISERROR(21505, 16, -1, @pubname)
  20186.                             return (1)
  20187.                         end
  20188.                 END
  20189.         end
  20190.  
  20191.     select sentgen, sentguid from MSmerge_replinfo where repid = @repid
  20192.     return (0)
  20193. go
  20194. exec dbo.sp_MS_marksystemobject sp_MSgetlastsentgen
  20195. go
  20196. grant exec on dbo.sp_MSgetlastsentgen to public
  20197. go
  20198.  
  20199. raiserror('Creating procedure sp_MSgetlastsentrecgens', 0,1)
  20200. GO
  20201.  
  20202. CREATE PROCEDURE sp_MSgetlastsentrecgens
  20203.     (@repid uniqueidentifier)
  20204. as
  20205.     declare @pubid         uniqueidentifier
  20206.     declare @pubname     sysname
  20207.     declare @status     int
  20208.     declare @retcode    int
  20209.  
  20210.     if (@repid is null)
  20211.         begin
  20212.             RAISERROR(14043, 16, -1, '@repid')
  20213.             return (1)
  20214.         end
  20215.     /*
  20216.     ** do permission checking
  20217.     */
  20218.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @repid = @repid
  20219.     if @retcode<>0 or @@ERROR<>0 return (1)
  20220.  
  20221.     /*
  20222.     ** Check the publication status at the publisher - if it is inactive ( say because of a 
  20223.     ** metadata cleanup event then return an error so the current merge will quit.
  20224.     */
  20225.     select @pubid = pubid from sysmergesubscriptions where subid = @repid
  20226.     if (@pubid is not null)
  20227.         begin
  20228.             EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
  20229.             IF @retcode = 0
  20230.                 BEGIN
  20231.  
  20232.                     select @pubname = name, @status = status from sysmergepublications where pubid = @pubid
  20233.                     if @status = 0
  20234.                         begin
  20235.                             RAISERROR(21505, 16, -1, @pubname)
  20236.                             return (1)
  20237.                         end
  20238.                 END
  20239.         end
  20240.  
  20241.     select sentgen, sentguid, recgen, recguid from MSmerge_replinfo where repid = @repid
  20242.     return (0)
  20243. go
  20244. exec dbo.sp_MS_marksystemobject sp_MSgetlastsentrecgens
  20245. go
  20246. grant exec on dbo.sp_MSgetlastsentrecgens to public
  20247.  
  20248. raiserror('Creating procedure sp_MSdummyupdate', 0,1)
  20249. GO
  20250.  
  20251.  
  20252. CREATE PROCEDURE sp_MSdummyupdate
  20253.     (@rowguid uniqueidentifier, @tablenick int, @metatype tinyint, @pubid uniqueidentifier = NULL, @uplineage tinyint = 1, @inlineage varbinary(255) = NULL, @incolv varbinary(2048) = NULL)
  20254. as
  20255.     declare @retcode     int
  20256.     declare @lineage     varbinary(255)
  20257.     declare    @conflict_lineage varbinary(255)
  20258.     declare @mynickname     int
  20259.     declare @col_tracking int
  20260.     declare @colv varbinary(2048)
  20261.     declare @reason nvarchar(255)
  20262.     declare @oldmaxversion int
  20263.  
  20264.     /*
  20265.     ** Check to see if current publication has permission
  20266.     */
  20267.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck    @tablenick = @tablenick, @pubid = @pubid
  20268.     if @retcode<>0 or @@ERROR<>0 return (1)
  20269.     
  20270.     /* Parameter checks */
  20271.     if (@rowguid is null)
  20272.         begin
  20273.         RAISERROR(14043, 16, -1, '@rowguid')
  20274.         return (1)
  20275.         end
  20276.     if (@tablenick is null)
  20277.         begin
  20278.         RAISERROR(14043, 16, -1, '@tablenick')
  20279.         return (1)
  20280.         end
  20281.     if (@metatype is null)
  20282.         begin
  20283.         RAISERROR(14043, 16, -1, '@metatype')
  20284.         return (1)
  20285.         end
  20286.  
  20287.     /* Check if we have a merge publication by whether system table is there */
  20288.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  20289.         begin
  20290.         RAISERROR(20054 , 16, -1)
  20291.         return (1)
  20292.         end
  20293.  
  20294.     exec dbo.sp_MSgetreplnick @nickname = @mynickname out
  20295.     if (@@error <> 0) or @mynickname IS NULL 
  20296.         begin
  20297.         RAISERROR (14055, 11, -1)
  20298.         RETURN(1)
  20299.         end                 
  20300.  
  20301.     -- Look for the "other" lineage in a conflict table
  20302.     select @conflict_lineage = max(lineage) from MSmerge_errorlineage where
  20303.         rowguid = @rowguid and tablenick = @tablenick
  20304.  
  20305.     set @oldmaxversion= (select top 1 maxversion_at_cleanup from sysmergearticles 
  20306.                             where nickname = @tablenick)
  20307.  
  20308.     if (@metatype = 0)
  20309.     begin
  20310.         /* We don't have the row.  Putting in a system delete tombstone should cause a delete and
  20311.         ** eventual convergence.  We are already logging the row as a conflict / error.
  20312.         */
  20313.         if @conflict_lineage is not null
  20314.         begin
  20315.             set @lineage = { fn UPDATELINEAGE(@conflict_lineage, @mynickname, @oldmaxversion+1) }
  20316.         end
  20317.         else
  20318.         begin
  20319.             set @lineage = { fn UPDATELINEAGE(0x0, @mynickname, @oldmaxversion+1) }
  20320.         end
  20321.         select @reason = formatmessage(20564) -- system delete
  20322.     
  20323.         insert into dbo.MSmerge_tombstone (rowguid, tablenick, type, lineage, generation, reason) 
  20324.             values (@rowguid, @tablenick, 6, @lineage, 0, @reason)
  20325.         
  20326.     end
  20327.     else if (@metatype = 1)
  20328.     begin
  20329.         if @inlineage is not null
  20330.         begin
  20331.             set @lineage = @inlineage
  20332.             set @lineage = { fn UPDATELINEAGE(@lineage, @mynickname, @oldmaxversion+1) }
  20333.         end
  20334.         else
  20335.         begin
  20336.             select @lineage = lineage from dbo.MSmerge_tombstone (UPDLOCK ROWLOCK index = 1) where tablenick = @tablenick and
  20337.                 rowguid = @rowguid
  20338.             if (@uplineage = 1)
  20339.             begin
  20340.                 if @conflict_lineage is not null
  20341.                 begin
  20342.                     exec @retcode= master..xp_mergelineages @lineage, @conflict_lineage, @lineage output
  20343.                     if @@error<>0 or @retcode<>0 return(1)
  20344.                 end
  20345.                 set @lineage = { fn UPDATELINEAGE(@lineage, @mynickname, @oldmaxversion+1) }
  20346.             end
  20347.         end
  20348.             
  20349.         update dbo.MSmerge_tombstone set generation = 0, lineage = @lineage where
  20350.             tablenick = @tablenick and rowguid = @rowguid
  20351.     end
  20352.     else if (@metatype = 2)
  20353.     begin
  20354.         if @inlineage is not null
  20355.         begin
  20356.             set @lineage = @inlineage
  20357.             set @lineage = { fn UPDATELINEAGE(@lineage, @mynickname, @oldmaxversion+1) }
  20358.  
  20359.             if @incolv is not null
  20360.             begin
  20361.                 set @colv = @incolv
  20362.             end
  20363.             else
  20364.             begin
  20365.                 select @colv = colv1 from dbo.MSmerge_contents (UPDLOCK ROWLOCK index = 1) where 
  20366.                     tablenick = @tablenick and rowguid = @rowguid
  20367.                 if @pubid is NULL
  20368.                     select @col_tracking = column_tracking from sysmergearticles where nickname = @tablenick
  20369.                 else
  20370.                     select @col_tracking = column_tracking from sysmergearticles where nickname = @tablenick and pubid = @pubid
  20371.                 if (@col_tracking = 0 or @colv is NULL)
  20372.                     set @colv = NULL
  20373.                 else
  20374.                     set @colv = { fn UPDATECOLVBM(@colv, @mynickname, 0x01, 0x00, { fn GETMAXVERSION(@lineage) }) }
  20375.             end
  20376.         end
  20377.         else
  20378.             -- @inlineage is null -> @incolv is null, too
  20379.         begin
  20380.             select @lineage = lineage, @colv = colv1 from dbo.MSmerge_contents (UPDLOCK ROWLOCK index = 1) where tablenick = @tablenick and
  20381.                 rowguid = @rowguid
  20382.             if (@uplineage = 1)
  20383.             begin
  20384.                 if @conflict_lineage is not null
  20385.                 begin
  20386.                     exec @retcode= master..xp_mergelineages @lineage, @conflict_lineage, @lineage output
  20387.                     if @@error<>0 or @retcode<>0 return(1)
  20388.                 end
  20389.                 set @lineage = { fn UPDATELINEAGE(@lineage, @mynickname, @oldmaxversion+1) }
  20390.                 if @pubid is NULL
  20391.                     select @col_tracking = column_tracking from sysmergearticles where nickname = @tablenick
  20392.                 else
  20393.                     select @col_tracking = column_tracking from sysmergearticles where nickname = @tablenick and pubid = @pubid
  20394.                 if (@col_tracking = 0 or @colv is NULL)
  20395.                     set @colv = NULL
  20396.                 else
  20397.                     set @colv = { fn UPDATECOLVBM(@colv, @mynickname, 0x01, 0x00, { fn GETMAXVERSION(@lineage) }) }
  20398.             end
  20399.         end
  20400.  
  20401.         update dbo.MSmerge_contents set generation = 0, lineage = @lineage, colv1 = @colv where
  20402.             tablenick = @tablenick and rowguid = @rowguid
  20403.     end
  20404.     else if (@metatype = 3)
  20405.     begin
  20406.         declare @ccols         int
  20407.         declare @sync_objid     int
  20408.         declare @missing_count int
  20409.  
  20410.         if @inlineage is not null
  20411.         begin
  20412.             set @lineage = @inlineage
  20413.             set @lineage = { fn UPDATELINEAGE(@lineage, @mynickname, @oldmaxversion+1) }
  20414.         end
  20415.         else if @conflict_lineage is not null
  20416.         begin
  20417.             set @lineage = { fn UPDATELINEAGE(@conflict_lineage, @mynickname, @oldmaxversion+1) }
  20418.         end
  20419.         else
  20420.         begin
  20421.             set @lineage = { fn UPDATELINEAGE(0x0, @mynickname, @oldmaxversion+1) }
  20422.         end
  20423.  
  20424.         if @incolv is not null
  20425.         begin
  20426.             set @colv = @incolv
  20427.         end
  20428.         else
  20429.         begin
  20430.             if @pubid is NULL
  20431.             begin
  20432.                 select @sync_objid = sync_objid, @col_tracking = column_tracking, @missing_count = missing_col_count
  20433.                  from sysmergearticles where nickname = @tablenick
  20434.             end
  20435.             else
  20436.             begin
  20437.                 select @sync_objid = sync_objid, @col_tracking = column_tracking, @missing_count = missing_col_count
  20438.                  from sysmergearticles where nickname = @tablenick and pubid = @pubid
  20439.             end
  20440.  
  20441.             if (@col_tracking = 0)
  20442.                 set @colv = NULL
  20443.             else
  20444.             begin
  20445.                 select @ccols= count(*) from syscolumns where id = @sync_objid
  20446.                 set @ccols = @ccols + @missing_count
  20447.                 set @colv = { fn INITCOLVS(@ccols, @mynickname ) }
  20448.             end
  20449.         end
  20450.  
  20451.         insert into dbo.MSmerge_contents (tablenick, rowguid, lineage, generation, colv1)
  20452.             values (@tablenick, @rowguid, @lineage, 0, @colv)
  20453.     end
  20454.     else if (@metatype = 6) -- e.g., used to cope with dup key / dup index
  20455.     begin
  20456.         if @conflict_lineage is not null
  20457.         begin
  20458.             set @lineage = { fn UPDATELINEAGE(@conflict_lineage, @mynickname, @oldmaxversion+1) }
  20459.         end
  20460.         else
  20461.         begin
  20462.             set @lineage = { fn UPDATELINEAGE(0x0, @mynickname, @oldmaxversion+1) }
  20463.         end
  20464.         select @reason = formatmessage(20564) -- system delete
  20465.     
  20466.         begin transaction
  20467.             if not exists (select * from MSmerge_tombstone where rowguid=@rowguid and tablenick=@tablenick)
  20468.             begin
  20469.                 insert into dbo.MSmerge_tombstone (rowguid, tablenick, type, lineage, generation, reason) 
  20470.                     values (@rowguid, @tablenick, @metatype, @lineage, 0, @reason)
  20471.             end
  20472.             delete from dbo.MSmerge_contents where rowguid=@rowguid and tablenick=@tablenick
  20473.         commit
  20474.     end
  20475.     return (0)
  20476. go
  20477. exec dbo.sp_MS_marksystemobject sp_MSdummyupdate
  20478. go
  20479. grant exec on dbo.sp_MSdummyupdate to public
  20480. go
  20481.  
  20482.  
  20483. raiserror('Creating procedure sp_MSsetlastrecgen', 0,1)
  20484. GO
  20485.  
  20486. CREATE PROCEDURE sp_MSsetlastrecgen
  20487.     (@repid uniqueidentifier, @srcgen int, @srcguid uniqueidentifier)
  20488. as
  20489.     /*
  20490.     ** Check to see if current publication has permission
  20491.     */
  20492.     declare @retcode     int
  20493.     declare @pubid         uniqueidentifier
  20494.     declare @pubname     sysname
  20495.     declare @status     int
  20496.  
  20497.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck    @repid = @repid
  20498.     if @retcode<>0 or @@ERROR<>0 return (1)
  20499.  
  20500.     if (@repid is null)
  20501.         begin
  20502.         RAISERROR(14043, 16, -1, '@repid')
  20503.         return (1)
  20504.         end
  20505.     if (@srcgen is null)
  20506.         begin
  20507.         RAISERROR(14043, 16, -1, '@srcgen')
  20508.         return (1)
  20509.         end
  20510.     if (@srcguid is null)
  20511.         begin
  20512.         RAISERROR(14043, 16, -1, '@srcguid')
  20513.         return (1)
  20514.         end
  20515.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  20516.         begin
  20517.         RAISERROR(20054 , 16, -1)
  20518.         return (1)
  20519.         end
  20520.  
  20521.     /*
  20522.     ** Check the publication status at the publisher - if it is inactive ( say because of a 
  20523.     ** metadata cleanup event then return an error so the current merge will quit.
  20524.     */
  20525.     select @pubid = pubid from sysmergesubscriptions where subid = @repid
  20526.     if (@pubid is not null)
  20527.         begin
  20528.             EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
  20529.             IF @retcode = 0
  20530.                 BEGIN
  20531.  
  20532.                     select @pubname = name, @status = status from sysmergepublications where pubid = @pubid
  20533.                     if @status = 0
  20534.                         begin
  20535.                             RAISERROR(21505, 16, -1, @pubname)
  20536.                             return (1)
  20537.                         end
  20538.                 END
  20539.         end
  20540.  
  20541.     update MSmerge_replinfo set recgen = @srcgen, recguid = @srcguid 
  20542.         where repid = @repid
  20543.     IF @@ERROR <>0 return (1) 
  20544.     return (0)
  20545. go
  20546. exec dbo.sp_MS_marksystemobject sp_MSsetlastrecgen
  20547. go
  20548. grant exec on dbo.sp_MSsetlastrecgen to public
  20549. go
  20550.  
  20551.  
  20552. dump tran master with no_log
  20553. go
  20554.  
  20555. raiserror('Creating procedure sp_MSsetlastsentgen', 0,1)
  20556. GO
  20557.  
  20558. CREATE PROCEDURE sp_MSsetlastsentgen
  20559.     (@repid uniqueidentifier, @srcgen int, @srcguid uniqueidentifier)
  20560. as
  20561.     /*
  20562.     ** Check to see if current publication has permission
  20563.     */
  20564.     declare @retcode     int
  20565.     declare @pubid         uniqueidentifier
  20566.     declare @pubname     sysname
  20567.     declare @status     int
  20568.  
  20569.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @repid = @repid
  20570.     if @retcode<>0 or @@ERROR<>0 return (1)
  20571.  
  20572.     if (@repid is null)
  20573.         begin
  20574.         RAISERROR(14043, 16, -1, '@repid')
  20575.         return (1)
  20576.         end
  20577.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  20578.         begin
  20579.         RAISERROR(20054 , 16, -1)
  20580.         return (1)
  20581.         end
  20582.  
  20583.     /*
  20584.     ** Check the publication status at the publisher - if it is inactive ( say because of a 
  20585.     ** metadata cleanup event then return an error so the current merge will quit.
  20586.     */
  20587.     select @pubid = pubid from sysmergesubscriptions where subid = @repid
  20588.     if (@pubid is not null)
  20589.         begin
  20590.             EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
  20591.             IF @retcode = 0
  20592.                 BEGIN
  20593.  
  20594.                     select @pubname = name, @status = status from sysmergepublications where pubid = @pubid
  20595.                     if @status = 0
  20596.                         begin
  20597.                             RAISERROR(21505, 16, -1, @pubname)
  20598.                             return (1)
  20599.                         end
  20600.                 END
  20601.         end
  20602.  
  20603.  
  20604.     /* 
  20605.     ** This is a special case which is used to update the anonymous subscriptions sent and 
  20606.     ** received generation guids at the end of initializing a dynamic subscription. This is 
  20607.     ** used in the case where an anonymous subscription is reinitialized after a merge metadata
  20608.     ** cleanup
  20609.     */
  20610.     if (@srcgen is null and @srcguid is null)
  20611.         begin
  20612.  
  20613.             declare @minnullgen         int
  20614.             declare @lastrecsentgen     int
  20615.             declare @lastrecsentguid     uniqueidentifier
  20616.             select @minnullgen = min(generation) from dbo.MSmerge_genhistory where guidlocal = '00000000-0000-0000-0000-000000000000'
  20617.             if @minnullgen IS NOT NULL
  20618.                 select @lastrecsentgen = max(generation) from dbo.MSmerge_genhistory where generation < @minnullgen
  20619.             if @lastrecsentgen IS NOT NULL
  20620.                 select @lastrecsentguid = guidsrc from dbo.MSmerge_genhistory where generation = @lastrecsentgen
  20621.             update MSmerge_replinfo  set sentgen= @lastrecsentgen, sentguid = @lastrecsentguid, recgen = @lastrecsentgen, recguid = @lastrecsentguid
  20622.                 where repid = @repid
  20623.             IF @@ERROR <>0 return (1)
  20624.         end
  20625.     else
  20626.         begin
  20627.             -- check for setting a sentgen which is obviously too high
  20628.             if (exists (select * from dbo.MSmerge_genhistory where generation < @srcgen and
  20629.                         guidlocal = '00000000-0000-0000-0000-000000000000' and
  20630.                         (art_nick = 0 or art_nick is null or art_nick in
  20631.                             (select nickname from sysmergearticles where
  20632.                                     pubid = @pubid) )))
  20633.                 begin
  20634.                 RAISERROR('Setting sentgen too high', 16, -1)
  20635.                 return (1)
  20636.                 end
  20637.             update MSmerge_replinfo  set sentgen= @srcgen, sentguid = @srcguid 
  20638.                 where repid = @repid
  20639.             IF @@ERROR <>0 return (1)
  20640.         end            
  20641.     return (0)
  20642. go
  20643. exec dbo.sp_MS_marksystemobject sp_MSsetlastsentgen
  20644. go
  20645. grant exec on dbo.sp_MSsetlastsentgen to public
  20646. go
  20647.  
  20648.  
  20649. raiserror('Creating procedure sp_MSenumgenerations', 0,1)
  20650. GO
  20651.  
  20652. CREATE PROCEDURE sp_MSenumgenerations
  20653.     (@genstart int, @pubid uniqueidentifier, @return_count_of_generations bit = 0)
  20654. as
  20655.     declare @retcode     smallint
  20656.     declare @guidnull     uniqueidentifier
  20657.     declare @generation_range TABLE (generation int NOT NULL, guidsrc uniqueidentifier NOT NULL, art_nick int NULL, guidlocal uniqueidentifier NOT NULL, pubid uniqueidentifier NULL, nicknames varbinary(1000) NOT NULL, okaytoskip bit NOT NULL)
  20658.     declare @status     int
  20659.     declare @pubname     sysname
  20660.     declare @rowcount    int
  20661.     set @guidnull = '00000000-0000-0000-0000-000000000000'
  20662.  
  20663.     /*
  20664.     ** Check to see if current publication has permission
  20665.     */
  20666.     if ({ fn ISPALUSER(@pubid) } <> 1)
  20667.     begin    
  20668.         RAISERROR (14126, 11, -1)
  20669.         return (1)
  20670.     end
  20671.  
  20672.     /*
  20673.     ** To public
  20674.     */
  20675.     
  20676.     if (@genstart is null)
  20677.         begin
  20678.         RAISERROR(14043, 16, -1, '@genstart')
  20679.         return (1)
  20680.         end
  20681.     if (@pubid is null)
  20682.         begin
  20683.         RAISERROR(14043, 16, -1, '@pubid')
  20684.         return (1)
  20685.         end
  20686.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  20687.         begin
  20688.         RAISERROR(20054 , 16, -1)
  20689.         return (1)
  20690.         end
  20691.     /*
  20692.     ** Check the publication status at the publisher - if it is inactive ( say because of a 
  20693.     ** metadata cleanup event then return an error so the current merge will quit.
  20694.     */
  20695.     EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
  20696.     IF @retcode = 0
  20697.         BEGIN
  20698.  
  20699.             select @pubname = name, @status = status from sysmergepublications where pubid = @pubid
  20700.             if @status = 0
  20701.                 begin
  20702.                     RAISERROR(21505, 16, -1, @pubname)
  20703.                     return (1)
  20704.                 end
  20705.         END
  20706.  
  20707.     insert into @generation_range (generation, guidsrc, art_nick, guidlocal, pubid, nicknames, okaytoskip)
  20708.     select DISTINCT generation, guidsrc, art_nick, guidlocal, pubid, nicknames, 0
  20709.     from dbo.MSmerge_genhistory 
  20710.     where generation >= @genstart 
  20711.     and (art_nick = 0 or art_nick is NULL or 
  20712.         art_nick in (select nickname from sysmergearticles 
  20713.         where pubid = @pubid)) 
  20714.     select @rowcount = @@rowcount
  20715.  
  20716.     if (@return_count_of_generations = 1)
  20717.         select @rowcount
  20718.  
  20719.     -- optimizations 
  20720.     -- 1. skip all rows that are for incomplete generations for articles that have no joins.
  20721.     -- 2. skip all rows for join articles if all the join article rows are incomplete generations.
  20722.  
  20723.     update @generation_range set okaytoskip = 1
  20724.     where art_nick is not null and art_nick <> 0
  20725.     and guidlocal = @guidnull 
  20726.     and 
  20727.     (
  20728.         (    
  20729.             -- 1. skip all rows that are for incomplete generations for articles that have no joins.
  20730.             not exists (select 1 from sysmergesubsetfilters where join_nickname = art_nick or art_nickname = art_nick)
  20731.         )
  20732.         or
  20733.         (    
  20734.             -- 2. skip all rows for join articles if all the rows for join and joined articles (i.e. the articles represented by join_nickname 
  20735.             --    and art_nickname in sysmergesubsetfilters) are incomplete generations.
  20736.  
  20737.             art_nick in (select join_nickname from sysmergesubsetfilters) 
  20738.             and not exists 
  20739.                 (    
  20740.                     select 1 from @generation_range b where b.guidlocal <> @guidnull 
  20741.                     and exists (select 1 from sysmergesubsetfilters where join_nickname = b.art_nick or art_nickname = b.art_nick)
  20742.                     and b.generation > @genstart
  20743.                 ) 
  20744.         )
  20745.     )
  20746.     
  20747.     select generation, guidsrc, art_nick, guidlocal, pubid, nicknames, okaytoskip from @generation_range
  20748.     ORDER BY generation ASC
  20749.  
  20750.     return (0)
  20751. go
  20752. exec dbo.sp_MS_marksystemobject sp_MSenumgenerations
  20753. go
  20754. grant exec on dbo.sp_MSenumgenerations to public
  20755. go
  20756. raiserror('Creating procedure sp_MScheckexistsgeneration', 0,1)
  20757. GO
  20758.  
  20759. CREATE PROCEDURE sp_MScheckexistsgeneration
  20760.     (@genguid uniqueidentifier, @gen int output, @pubid uniqueidentifier = NULL)
  20761. as
  20762.     /*
  20763.     ** Check input parameter
  20764.     */
  20765.     if (@genguid is null)
  20766.         begin
  20767.             RAISERROR(14043, 16, -1, '@genguid')
  20768.             return (1)
  20769.         end
  20770.     /*
  20771.     ** check permission
  20772.     */
  20773.     if @pubid is not NULL
  20774.     begin
  20775.         if ({ fn ISPALUSER(@pubid) } <> 1)
  20776.         begin    
  20777.             RAISERROR (14126, 11, -1)
  20778.             return (1)
  20779.  
  20780.         end
  20781.     end
  20782.     else
  20783.     begin
  20784.         if not exists (select * from dbo.sysmergepublications 
  20785.                                 where 1 = {fn ISPALUSER(pubid)})
  20786.         begin
  20787.             RAISERROR (14126, 11, -1)
  20788.             return (1)
  20789.         end    
  20790.     end
  20791.     /* Normal case : do not qualify by pubid */
  20792.     if (@pubid IS NULL)
  20793.         select @gen = max(generation) from dbo.MSmerge_genhistory where guidsrc = @genguid and guidlocal <> '00000000-0000-0000-0000-000000000000'
  20794.     else        
  20795.     /* If we are reinitializing from an alternate publisher, check if the subscription has received generations for the alternate publication */
  20796.         select @gen = max(generation) from dbo.MSmerge_genhistory where guidsrc = @genguid and guidlocal <> '00000000-0000-0000-0000-000000000000'
  20797.             and ((pubid = @pubid) or (pubid is null))
  20798.     IF @@ERROR <>0 return (1)
  20799.     return (0)
  20800. go
  20801. exec dbo.sp_MS_marksystemobject sp_MScheckexistsgeneration
  20802. go
  20803. grant exec on dbo.sp_MScheckexistsgeneration to public
  20804. GO
  20805.  
  20806. CREATE PROCEDURE sp_MSchecksnapshotstatus
  20807.     @publication        sysname
  20808. AS
  20809.     declare @db_name        sysname
  20810.     declare @retention        int
  20811.     declare @snapshot_ready    int
  20812.     declare @pubid            uniqueidentifier
  20813.     declare @last_snapshot     datetime
  20814.     
  20815.     select @snapshot_ready = NULL
  20816.     select @db_name = db_name()
  20817.  
  20818.     select @snapshot_ready=snapshot_ready, @retention=retention, @pubid=pubid
  20819.         from dbo.sysmergepublications where name=@publication and publisher=@@SERVERNAME and publisher_db=@db_name
  20820.     if @snapshot_ready is NULL
  20821.         select @snapshot_ready=snapshot_ready, @retention=retention, @pubid=pubid
  20822.             from dbo.sysmergepublications where name=@publication
  20823.     if @snapshot_ready is NULL
  20824.     begin
  20825.         raiserror (20026, 11, -1, @publication)
  20826.         return (1)
  20827.     end
  20828.     
  20829.     if @snapshot_ready=1 and @retention>0
  20830.     begin
  20831.         select @last_snapshot=last_validated from sysmergesubscriptions where subid=@pubid
  20832.         if dateadd(day, @retention, @last_snapshot)<getdate()
  20833.             select @snapshot_ready=3 /* snapshot is obsolete */
  20834.     end
  20835.     select @snapshot_ready
  20836. go
  20837. exec dbo.sp_MS_marksystemobject sp_MSchecksnapshotstatus
  20838. go
  20839. grant exec on dbo.sp_MSchecksnapshotstatus to public
  20840.  
  20841. raiserror('Creating procedure sp_MSenumreplicas', 0,1)
  20842. GO
  20843.  
  20844. CREATE PROCEDURE sp_MSenumreplicas (@pubid uniqueidentifier)
  20845. as
  20846.     declare @inactive tinyint
  20847.  
  20848.     /*
  20849.     ** Check to see if current publication has permission
  20850.     */
  20851.     if ({ fn ISPALUSER(@pubid) } <> 1)
  20852.     begin    
  20853.         RAISERROR (14126, 11, -1)
  20854.         return (1)
  20855.     end
  20856.  
  20857.     /*
  20858.     ** To public
  20859.     */
  20860.  
  20861.     select @inactive = 0
  20862.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  20863.     begin
  20864.         RAISERROR(20054 , 16, -1)
  20865.         return (1)
  20866.     end
  20867.  
  20868.     select subs.subid, replinfo.replnickname, subs.subscriber_type, subs.subscription_type, 
  20869.         subs.priority, replinfo.schemaversion, replinfo.schemaguid, subs.datasource_type, subs.datasource_path, servers.srvname,  
  20870.         subs.db_name, subs.status, subs.partnerid, subs.sync_type, subs.description, subs.pubid, subs.publication, subs.distributor
  20871.         from sysmergesubscriptions subs, MSmerge_replinfo replinfo, master..sysservers servers
  20872.             where replinfo.repid = subs.subid 
  20873.                 and subs.srvid = servers.srvid
  20874.                 and subs.status <> @inactive
  20875.                 and subs.subscriber_type = 1
  20876.                 order by convert(binary, subs.subid)
  20877.     IF @@ERROR <>0 return (1) 
  20878.     return (0)
  20879. go
  20880. exec dbo.sp_MS_marksystemobject sp_MSenumreplicas 
  20881. go
  20882. grant exec on dbo.sp_MSenumreplicas to public
  20883.  
  20884. raiserror('Creating procedure sp_MSenumdeletesmetadata', 0,1)
  20885. GO
  20886.  
  20887. CREATE PROCEDURE sp_MSenumdeletesmetadata(
  20888.     @pubid uniqueidentifier, 
  20889.     @maxrows int, 
  20890.     @genlist varchar(8000), 
  20891.     @tablenick int, 
  20892.     @rowguid     uniqueidentifier,
  20893.     @filter_partialdeletes int = 0,
  20894.     @specified_article_only int = 0,
  20895.     @mingen    int = 0,
  20896.     @maxgen int = 0)
  20897. as
  20898.     declare @tnstring nvarchar(12)
  20899.     declare @rgstring nvarchar(38)
  20900.     declare @pubidstr nvarchar(38)
  20901.     declare @tablenick_qual nvarchar(100)
  20902.     declare @maxgenmingen_clause nvarchar(100)
  20903.  
  20904.     /*
  20905.     ** To public.
  20906.     */
  20907.     if ({ fn ISPALUSER(@pubid) } <> 1)
  20908.     begin    
  20909.         RAISERROR (14126, 11, -1)
  20910.         return (1)
  20911.     end
  20912.  
  20913.     if (@genlist is null)
  20914.     begin
  20915.         RAISERROR(14043, 16, -1, '@genlist')
  20916.         return (1)
  20917.     end
  20918.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  20919.     begin
  20920.         RAISERROR(20054 , 16, -1)
  20921.         return (1)
  20922.     end
  20923.             
  20924.  
  20925.     set @pubidstr = '''' + convert(nchar(36), @pubid) + ''''
  20926.  
  20927.     /* If the filter_partialdeletes is NOT set, include all types of tombstones, else filter the type = 5 ones */
  20928.     if (@filter_partialdeletes = 0)
  20929.         set @tablenick_qual = '    and ts.tablenick = sm.nickname '
  20930.     else
  20931.         set @tablenick_qual = '    and ts.tablenick = sm.nickname and ts.type <> 5'
  20932.     
  20933.     declare @selecttop nvarchar(20)
  20934.     if (@maxrows = 0)
  20935.         set @selecttop= 'select'
  20936.     else
  20937.         set @selecttop= 'select top ' + cast(@maxrows as nvarchar(9)) 
  20938.     
  20939.     declare @mingenstr nvarchar(13)
  20940.     declare @maxgenstr nvarchar(13)
  20941.  
  20942.     select @mingenstr = convert(nchar, @mingen)
  20943.     select @maxgenstr = convert(nchar, @maxgen)
  20944.  
  20945.     if (@maxgen = 0)
  20946.         select @maxgenmingen_clause = ' '
  20947.     else
  20948.         select @maxgenmingen_clause = ' generation >= ' + @mingenstr + ' and generation <= ' + @maxgenstr + ' and '
  20949.  
  20950.     if (@tablenick = 0)
  20951.     begin
  20952.         if (@genlist is not null and rtrim(ltrim(@genlist)) <> '')
  20953.         begin
  20954.             execute (@selecttop + ' tablenick, rowguid, generation, lineage, ts.type from dbo.MSmerge_tombstone ts, sysmergearticles sm
  20955.                 where ' + @maxgenmingen_clause + ' generation in (' + @genlist + ') 
  20956.                 and sm.pubid = ' + @pubidstr + @tablenick_qual + '
  20957.                 order by tablenick desc, rowguid asc' )
  20958.  
  20959.             IF @@ERROR <>0 
  20960.             begin
  20961.                 return (1)     
  20962.             end
  20963.  
  20964.  
  20965.         end
  20966.     end
  20967.     else
  20968.     begin
  20969.         set @tnstring = convert(nchar, @tablenick)
  20970.         set @rgstring = '''' + convert(nchar(36), @rowguid) + ''''
  20971.         if (@genlist is not null and rtrim(ltrim(@genlist)) <> '')
  20972.         begin
  20973.             if (@specified_article_only = 1)
  20974.             begin
  20975.                 execute (@selecttop + ' tablenick, rowguid, generation, lineage, ts.type from dbo.MSmerge_tombstone ts, sysmergearticles sm
  20976.                     where ' + @maxgenmingen_clause + ' generation in (' + @genlist + ') and 
  20977.                     tablenick = ' + @tnstring + ' and 
  20978.                     rowguid > ' + @rgstring + ' 
  20979.                     and sm.pubid = ' + @pubidstr + @tablenick_qual + ' 
  20980.                     order by rowguid' )
  20981.  
  20982.                 IF @@ERROR <>0 
  20983.                 begin
  20984.                     return (1)     
  20985.                 end
  20986.  
  20987.             end
  20988.             else
  20989.             begin
  20990.                 execute (@selecttop + ' tablenick, rowguid, generation, lineage, ts.type from dbo.MSmerge_tombstone ts, sysmergearticles sm
  20991.                     where ' + @maxgenmingen_clause + ' generation in (' + @genlist + ') and 
  20992.                     ((tablenick = ' + @tnstring + ' and 
  20993.                     rowguid > ' + @rgstring + ') or
  20994.                     tablenick < ' + @tnstring + ') 
  20995.                     and sm.pubid = ' + @pubidstr + @tablenick_qual + ' 
  20996.                     order by tablenick desc, rowguid asc' )
  20997.  
  20998.                 IF @@ERROR <>0 
  20999.                 begin
  21000.                     return (1)     
  21001.                 end
  21002.  
  21003.             end
  21004.         end
  21005.     end
  21006.  
  21007.     return (0)
  21008. go
  21009. exec dbo.sp_MS_marksystemobject sp_MSenumdeletesmetadata 
  21010. go
  21011. grant exec on dbo.sp_MSenumdeletesmetadata to public
  21012. go
  21013. raiserror('Creating procedure sp_MSenumpartialdeletes', 0,1)
  21014. GO
  21015.  
  21016. CREATE PROCEDURE sp_MSenumpartialdeletes
  21017.     (@maxrows int,
  21018.      @tablenick int,
  21019.      @rowguid uniqueidentifier,
  21020.      @tablenotbelongs nvarchar(255),
  21021.      @bookmark int = NULL,
  21022.      @specified_article_only int = 0)
  21023. as
  21024.  
  21025.     declare @tnstring         nvarchar(12)
  21026.     declare @rgstring         nvarchar(38)
  21027.     declare @lowrangestr     nvarchar(12) 
  21028.     declare @highrangestr     nvarchar(12) 
  21029.     declare @retcode        int
  21030.     
  21031.     /*
  21032.     ** do permission checking
  21033.     */
  21034.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick = @tablenick
  21035.     if @retcode<>0 or @@ERROR<>0 return (1)
  21036.  
  21037.     /*
  21038.     ** To public.
  21039.     */
  21040.     
  21041.     declare @selecttop nvarchar(20)
  21042.     if (@maxrows = 0)
  21043.         set @selecttop= 'select'
  21044.     else
  21045.         set @selecttop= 'select top ' + cast(@maxrows as nvarchar(9)) 
  21046.  
  21047.  
  21048.     if (@tablenick < 1)
  21049.     begin
  21050.         execute (@selecttop + ' tablenick, rowguid, COALESCE (generation, 0), lineage, type, bookmark from ' + @tablenotbelongs + '
  21051.                     order by tablenick desc, rowguid asc' )
  21052.         IF @@ERROR <>0 
  21053.         begin
  21054.             return (1)     
  21055.         end
  21056.  
  21057.     end
  21058.     else 
  21059.     begin
  21060.         set @tnstring = convert(nchar, @tablenick)
  21061.         set @rgstring = '''' + convert(nchar(36), @rowguid) + ''''
  21062.  
  21063.         /* 
  21064.         ** If a 7.0 SP1 Merge agent is calling this sp, it passed a valid bookmark parameter 
  21065.         ** Use the bookmark column in the ##belongs_<> table to retrieve the next batch of rows
  21066.         */
  21067.         if @bookmark is NOT NULL 
  21068.         begin
  21069.             set @lowrangestr = convert(nchar, @bookmark)
  21070.             set @highrangestr = convert(nchar, (@bookmark + @maxrows))
  21071.  
  21072.             if (@specified_article_only = 1)
  21073.             begin
  21074.                 -- don't rely on @highrangestr since it will be equal to @lowrangestr if @maxrows=0.
  21075.                 execute (@selecttop + ' tablenick, rowguid, COALESCE (generation, 0), lineage, type, bookmark from ' + @tablenotbelongs + '
  21076.                             where  tablenick = ' + @tnstring + ' and 
  21077.                             bookmark > ' + @lowrangestr + ' 
  21078.                             order by rowguid' )
  21079.  
  21080.                 if @@ERROR<>0
  21081.                 begin
  21082.                     return (1)
  21083.                 end                        
  21084.  
  21085.  
  21086.             end
  21087.             else
  21088.             begin
  21089.                 execute ('select tablenick, rowguid, COALESCE (generation, 0), lineage, type, bookmark from ' + @tablenotbelongs + '
  21090.                             where  ((tablenick = ' + @tnstring + ' and 
  21091.                             bookmark > ' + @lowrangestr + ' and bookmark <= ' + @highrangestr + ') or
  21092.                             tablenick < ' + @tnstring + ') 
  21093.                             order by tablenick desc, rowguid asc' )
  21094.  
  21095.                 if @@ERROR<>0
  21096.                 begin
  21097.                     return (1)
  21098.                 end                        
  21099.  
  21100.             end
  21101.         end
  21102.  
  21103.         /* 
  21104.         ** Backward compatibilty mode : If a 7.0 Merge agent is calling this sp, it will pass a NULL bookmark parameter 
  21105.         ** Use the rowguid and set rowcount to retrieve the next batch of rows
  21106.         */
  21107.         else
  21108.         begin
  21109.             if (@specified_article_only = 1)
  21110.             begin
  21111.                 execute (@selecttop + ' tablenick, rowguid, COALESCE (generation, 0), lineage, type from ' + @tablenotbelongs + '
  21112.                             where  tablenick = ' + @tnstring + ' and rowguid > ' + @rgstring + '
  21113.                             order by rowguid' )
  21114.                 IF @@ERROR <>0 
  21115.                 begin
  21116.                     return (1)     
  21117.                 end
  21118.  
  21119.             end
  21120.             else
  21121.             begin
  21122.                 execute (@selecttop + ' tablenick, rowguid, COALESCE (generation, 0), lineage, type from ' + @tablenotbelongs + '
  21123.                             where  ((tablenick = ' + @tnstring + ' and 
  21124.                             rowguid > ' + @rgstring + ') or tablenick < ' + @tnstring + ') 
  21125.                             order by tablenick desc, rowguid asc' )
  21126.                 IF @@ERROR <>0 
  21127.                 begin
  21128.                     return (1)     
  21129.                 end
  21130.  
  21131.             end
  21132.         end
  21133.     end
  21134.     return (0)
  21135. go        
  21136. exec dbo.sp_MS_marksystemobject sp_MSenumpartialdeletes
  21137. go
  21138. grant exec on dbo.sp_MSenumpartialdeletes to public
  21139. go
  21140.  
  21141.  
  21142. raiserror('Creating procedure sp_MSenumchanges', 0,1)
  21143. GO
  21144. CREATE PROCEDURE sp_MSenumchanges
  21145.     (@maxrows int, @genlist varchar(8000), @tablenick int, @rowguid uniqueidentifier, @pubid uniqueidentifier = NULL,
  21146.         @oldmaxgen int=0, @mingen    int = 0, @maxgen int = 0)
  21147. as
  21148.     declare @tnstring    nvarchar(12)
  21149.     declare @oldmaxgenstr  nvarchar(12)
  21150.     declare @rgstring     nvarchar(38)
  21151.     declare @retcode     smallint
  21152.     declare @procname    nvarchar(270)
  21153.     declare @maxgenmingen_clause nvarchar(100)
  21154.  
  21155.     /*
  21156.     ** To public.
  21157.     */
  21158.     if (@tablenick is null)
  21159.     begin
  21160.         RAISERROR(14043, 16, -1, '@tablenick')
  21161.         return (1)
  21162.     end
  21163.  
  21164.     -- security check
  21165.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick=@tablenick, @pubid = @pubid
  21166.     if @@error <> 0 or @retcode <> 0
  21167.         return 1
  21168.  
  21169.     if (@genlist is null)
  21170.     begin
  21171.         RAISERROR(14043, 16, -1, '@genlist')
  21172.         return (1)
  21173.     end
  21174.  
  21175.     create table #cont (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, generation int NULL, lineage varbinary(249) NULL    , colv1 varbinary(2048) NULL)
  21176.     
  21177.     set @tnstring = convert(nchar, @tablenick)
  21178.     set @rgstring = '''' + convert(nchar(36), @rowguid) + ''''
  21179.  
  21180.     declare @selecttop nvarchar(20)
  21181.     if (@maxrows = 0)
  21182.         set @selecttop= 'select'
  21183.     else
  21184.         set @selecttop= 'select top ' + cast(@maxrows as nvarchar(9)) 
  21185.  
  21186.     declare @mingenstr nvarchar(13)
  21187.     declare @maxgenstr nvarchar(13)
  21188.  
  21189.     select @mingenstr = convert(nchar, @mingen)
  21190.     select @maxgenstr = convert(nchar, @maxgen)
  21191.  
  21192.     if (@maxgen = 0)
  21193.         select @maxgenmingen_clause = ' '
  21194.     else
  21195.         select @maxgenmingen_clause = ' generation >= ' + @mingenstr + ' and generation <= ' + @maxgenstr + ' and '
  21196.  
  21197.     if (@genlist is not null and rtrim(ltrim(@genlist)) <> '')
  21198.     begin
  21199.         if @oldmaxgen > 0
  21200.         begin
  21201.         set @oldmaxgenstr = convert(nchar, @oldmaxgen)
  21202.         execute ('insert into #cont ' +
  21203.                     @selecttop + ' tablenick, rowguid, generation, lineage, colv1
  21204.                              from dbo.MSmerge_contents where 
  21205.                             (
  21206.                                 (
  21207.                                     ' + @maxgenmingen_clause + ' generation in (' + @genlist + ')
  21208.                                 )
  21209.                                 or generation = 0 or generation > ' + @oldmaxgenstr + '
  21210.                             ) 
  21211.                             and tablenick = ' + @tnstring + ' 
  21212.                             and rowguid > ' + @rgstring +     ' 
  21213.                             order by rowguid' )
  21214.         end
  21215.         else
  21216.         execute ('insert into #cont ' +
  21217.                     @selecttop + ' tablenick, rowguid, generation, lineage, colv1
  21218.                              from dbo.MSmerge_contents where ' + @maxgenmingen_clause + ' generation in (' + @genlist + ') and 
  21219.                         tablenick = ' + @tnstring + ' and rowguid > ' + @rgstring +
  21220.                             ' order by rowguid' )
  21221.         if @@ERROR <>0 
  21222.         begin
  21223.             return (1)
  21224.         end
  21225.     end
  21226.  
  21227.     select @procname = select_proc from sysmergearticles where nickname=@tablenick and pubid = @pubid
  21228.     exec @retcode = @procname @type=2
  21229.     IF @@ERROR<>0 or @retcode<>0
  21230.     begin
  21231.         RETURN (1)
  21232.     end
  21233.  
  21234.  
  21235.  
  21236.     drop table #cont
  21237.     return (0)
  21238. go
  21239. exec dbo.sp_MS_marksystemobject sp_MSenumchanges
  21240. go
  21241. grant exec on dbo.sp_MSenumchanges to public
  21242. go
  21243.  
  21244. raiserror('Creating procedure sp_MSenumpartialchanges', 0,1)
  21245. GO
  21246.  
  21247. CREATE PROCEDURE sp_MSenumpartialchanges
  21248.     (@maxrows int, @temp_cont sysname, @tablenick int, @rowguid uniqueidentifier, @pubid uniqueidentifier = NULL)
  21249. as
  21250.     declare @retcode         smallint
  21251.     declare @tnstring         nvarchar(12)
  21252.     declare @rgstring         nvarchar(38)
  21253.     -- Owner qualified
  21254.     declare @procname        nvarchar(270)
  21255.     
  21256.     if (@tablenick is null)
  21257.         begin
  21258.         RAISERROR(14043, 16, -1, '@tablenick')
  21259.         return (1)
  21260.         end
  21261.  
  21262.     -- security check
  21263.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick=@tablenick, @pubid = @pubid
  21264.     if @@error <> 0 or @retcode <> 0
  21265.         return 1
  21266.         
  21267.     set @tnstring = convert(nchar, @tablenick)
  21268.     set @rgstring = '''' + convert(nchar(36), @rowguid) + ''''
  21269.  
  21270.     create table #cont (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, generation int NULL, lineage varbinary(249) NULL    ,colv1 varbinary(2048) NULL)
  21271.     
  21272.     declare @selecttop nvarchar(20)
  21273.     if (@maxrows = 0)
  21274.         set @selecttop= 'select'
  21275.     else
  21276.         set @selecttop= 'select top ' + cast(@maxrows as nvarchar(9)) 
  21277.     
  21278.     execute ('insert into #cont ' +
  21279.                     @selecttop + ' tablenick, rowguid, generation, lineage, colv from ' + @temp_cont + ' where
  21280.                             tablenick = ' + @tnstring + ' and rowguid > ' + @rgstring
  21281.                             + ' order by rowguid')
  21282.     if @@ERROR<>0
  21283.     begin
  21284.         return (1)
  21285.     end                        
  21286.  
  21287.     select @procname = select_proc from sysmergearticles where nickname=@tablenick and pubid = @pubid
  21288.     
  21289.     exec @retcode = @procname @type =3
  21290.     IF @@ERROR<>0 or @retcode<>0 
  21291.     begin
  21292.         RETURN (1)
  21293.     end
  21294.  
  21295.  
  21296.  
  21297.     drop table #cont
  21298.     return (0)
  21299. go
  21300. exec dbo.sp_MS_marksystemobject sp_MSenumpartialchanges
  21301. go
  21302. grant exec on dbo.sp_MSenumpartialchanges to public
  21303.  
  21304.  
  21305. raiserror('Creating procedure sp_MSinitdynamicsubscriber', 0,1)
  21306. GO
  21307.  
  21308. CREATE PROCEDURE sp_MSinitdynamicsubscriber
  21309.     (@maxrows int, @tablenick int, @rowguid uniqueidentifier, @pubid uniqueidentifier = NULL)
  21310. as
  21311.     declare @retcode         smallint
  21312.     declare @procname        nvarchar(290)
  21313.     /*
  21314.     ** To public.
  21315.     */
  21316.     
  21317.     if (@tablenick is null)
  21318.         begin
  21319.         RAISERROR(14043, 16, -1, '@tablenick')
  21320.         return (1)
  21321.         end
  21322.  
  21323.     -- security check
  21324.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @pubid=@pubid, @tablenick=@tablenick
  21325.     if @@error <> 0 or @retcode <> 0
  21326.         return 1
  21327.     
  21328.     select @procname = view_sel_proc from sysmergearticles where
  21329.             pubid = @pubid and nickname = @tablenick
  21330.     exec @retcode = @procname @tablenick, @maxrows, @rowguid
  21331.     if @@ERROR<>0 or @retcode<>0 
  21332.         begin
  21333.             return (1)
  21334.         end    
  21335.     return (0)
  21336. go
  21337. exec dbo.sp_MS_marksystemobject sp_MSinitdynamicsubscriber
  21338. go
  21339. grant exec on dbo.sp_MSinitdynamicsubscriber to public
  21340.  
  21341.  
  21342. raiserror('Creating procedure sp_MSgetrowmetadata', 0,1)
  21343. GO
  21344.  
  21345. CREATE PROCEDURE sp_MSgetrowmetadata
  21346.     (@tablenick int,
  21347.      @rowguid uniqueidentifier,
  21348.      @generation int output,
  21349.      @type  tinyint output,
  21350.      @lineage varbinary(255) output,
  21351.      @colv varbinary(2048) output,
  21352.      @pubid uniqueidentifier = NULL)
  21353. as
  21354.     declare @retcode         smallint
  21355.     declare @saverr         int
  21356.     declare @rc             int
  21357.     declare @procname         nvarchar(270)
  21358.     
  21359.     /*
  21360.     ** To public.
  21361.     */
  21362.     
  21363.     
  21364.     if (@tablenick is null)
  21365.         begin
  21366.         RAISERROR(14043, 16, -1, '@tablenick')
  21367.         return (1)
  21368.         end
  21369.     
  21370.     -- security check
  21371.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick=@tablenick, @pubid = @pubid
  21372.     if @@error <> 0 or @retcode <> 0
  21373.         return 1
  21374.  
  21375.     if (@rowguid is null)
  21376.         begin
  21377.         RAISERROR(14043, 16, -1, '@rowguid')
  21378.         return (1)
  21379.         end
  21380.  
  21381.     set @type= 4
  21382.     set @generation= 0
  21383.     set @lineage= NULL
  21384.     set @colv= NULL
  21385.  
  21386.     select @procname= select_proc from sysmergearticles where nickname = @tablenick and pubid = @pubid
  21387.  
  21388.     -- check for row in base table
  21389.     exec @retcode= @procname @type=@type output, @rowguid=@rowguid
  21390.     if @@error <>0 or @retcode <> 0 
  21391.     begin
  21392.         return (1)
  21393.     end
  21394.  
  21395.     begin tran
  21396.     if (@type = 3)
  21397.     begin
  21398.         -- row is in base table; check whether it is in contents, too
  21399.         --
  21400.         -- serializable makes sure row does not go from tombstone to contents between 
  21401.         -- querying contents and tombstone, which would falsely result in type = missing
  21402.         select @type= 2,  @generation= generation, @lineage= lineage, @colv= colv1 from dbo.MSmerge_contents
  21403.             with (serializable)
  21404.             where tablenick = @tablenick and rowguid = @rowguid
  21405.     end
  21406.     else
  21407.     begin
  21408.         -- row is not in base table; either it is in tombstone, or it is missing
  21409.         set @type= 0
  21410.  
  21411.         select @type= type, @generation= generation, @lineage= lineage from dbo.MSmerge_tombstone where
  21412.             tablenick = @tablenick and rowguid = @rowguid
  21413.     end
  21414.     commit tran
  21415.     
  21416.     return (0)
  21417. go
  21418. exec dbo.sp_MS_marksystemobject sp_MSgetrowmetadata
  21419. go
  21420. grant exec on dbo.sp_MSgetrowmetadata to public
  21421. go
  21422.  
  21423.  
  21424. raiserror('Creating procedure sp_MSgetmetadatabatch', 0,1)
  21425. GO
  21426.  
  21427. CREATE PROCEDURE sp_MSgetmetadatabatch
  21428.     (@pubid uniqueidentifier,
  21429.      @tablenickarray varbinary(2000),
  21430.      @rowguidarray varbinary(8000)
  21431.     )
  21432. as
  21433.     declare @tablenick int
  21434.     declare @tablenicklast int
  21435.     declare @rowguid uniqueidentifier
  21436.     declare @generation int 
  21437.     declare @type  tinyint
  21438.     declare @lineage varbinary(255) 
  21439.     declare @colv varbinary(2048)
  21440.     declare @retcode         smallint
  21441.     declare @saverr         int
  21442.     declare @tnlength        int
  21443.     declare @tnoffset        int
  21444.     declare @guidoffset        int
  21445.     declare @procname         nvarchar(270)
  21446.  
  21447.     -- create temp table for returning results
  21448.     declare  @meta_batch TABLE (idx int identity, generation int, type  tinyint,
  21449.              lineage varbinary(255), colv varbinary(2048))
  21450.  
  21451.     -- security check
  21452.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @pubid=@pubid
  21453.     if @@error <> 0 or @retcode <> 0
  21454.         return 1
  21455.     
  21456.     if (@tablenickarray is null)
  21457.         begin
  21458.         RAISERROR(14043, 16, -1, '@tablenick')
  21459.         return (1)
  21460.         end
  21461.     if (@rowguidarray is null)
  21462.         begin
  21463.         RAISERROR(14043, 16, -1, '@rowguid')
  21464.         return (1)
  21465.         end
  21466.     
  21467.     set @tablenicklast = 0
  21468.     -- initialize offsets and length for walking through arrays
  21469.     set @tnoffset = 1
  21470.     set @guidoffset = 1
  21471.     set @tnlength = datalength(@tablenickarray)
  21472.  
  21473.  
  21474.     -- walk through arrays and populate temp table
  21475.     while (@tnoffset < @tnlength)
  21476.         begin
  21477.         set @tablenick = substring(@tablenickarray, @tnoffset, 4)
  21478.         set @rowguid = substring(@rowguidarray, @guidoffset, 16)
  21479.  
  21480.         -- instead of calling sp_MSgetrowmetadata, look it up ourselves might be faster
  21481.         
  21482.         --    exec @rc = sp_MSgetrowmetadata @tablenick, @rowguid,  @generation output,
  21483.          --    @type  output, @lineage output, @colv output, @pubid
  21484.         if @tablenick <> @tablenicklast
  21485.             begin
  21486.             select @procname = select_proc from sysmergearticles where nickname = @tablenick and pubid=@pubid
  21487.             set @tablenicklast = @tablenick
  21488.             end
  21489.  
  21490.         set @type= 4
  21491.         set @generation= 0
  21492.         set @lineage= NULL
  21493.         set @colv= NULL
  21494.  
  21495.         -- check for row in base table
  21496.         exec @retcode= @procname @type=@type output, @rowguid=@rowguid
  21497.         if @@error <>0 or @retcode <> 0 
  21498.         begin
  21499.             return (1)
  21500.         end
  21501.  
  21502.         begin tran
  21503.         if (@type = 3)
  21504.         begin
  21505.             -- row is in base table; check whether it is in contents, too
  21506.             --
  21507.             -- serializable makes sure row does not go from tombstone to contents between 
  21508.             -- querying contents and tombstone, which would falsely result in type = missing
  21509.             select @type= 2,  @generation= generation, @lineage= lineage, @colv= colv1 from dbo.MSmerge_contents
  21510.                 with (serializable)
  21511.                 where tablenick = @tablenick and rowguid = @rowguid
  21512.         end
  21513.         else
  21514.         begin
  21515.             -- row is not in base table; either it is in tombstone, or it is missing
  21516.             set @type= 0
  21517.  
  21518.             select @type= type, @generation= generation, @lineage= lineage from dbo.MSmerge_tombstone where
  21519.                 tablenick = @tablenick and rowguid = @rowguid
  21520.         end
  21521.         commit tran
  21522.  
  21523.  
  21524.          -- insert values into temp table
  21525.          insert into @meta_batch (generation, type, lineage, colv) values
  21526.              (@generation, @type, @lineage, @colv) 
  21527.  
  21528.          -- bump up offsets for next time through loop
  21529.          set @tnoffset = @tnoffset + 4
  21530.          set @guidoffset = @guidoffset + 16
  21531.         end
  21532.  
  21533.     -- select out our result set
  21534.     select generation, type, lineage, colv from @meta_batch order by idx
  21535.     
  21536.     return (0)
  21537. go
  21538. exec dbo.sp_MS_marksystemobject sp_MSgetmetadatabatch
  21539. go
  21540. grant exec on dbo.sp_MSgetmetadatabatch to public
  21541. go
  21542.  
  21543. raiserror('Creating procedure sp_MSsetrowmetadata', 0,1)
  21544. GO
  21545.  
  21546. CREATE PROCEDURE sp_MSsetrowmetadata
  21547.     (@tablenick int, @rowguid uniqueidentifier, @generation int,
  21548.      @lineage varbinary(255), @colv varbinary(2048), @type tinyint,
  21549.      @pubid uniqueidentifier = NULL,
  21550.      @tombstone_rows_deleted int = NULL OUTPUT)
  21551. as
  21552.     declare @reason nvarchar(255), @retcode int
  21553.             
  21554.     if (@tablenick is null)
  21555.     begin
  21556.         RAISERROR(14043, 16, -1, '@tablenick')
  21557.         return (1)
  21558.     end
  21559.     if (@rowguid is null)
  21560.     begin
  21561.         RAISERROR(14043, 16, -1, '@rowguid')
  21562.         return (1)
  21563.     end
  21564.     if (@generation is null)
  21565.     begin
  21566.         RAISERROR(14043, 16, -1, '@generation')
  21567.         return (1)
  21568.     end
  21569.     if (@lineage is null)
  21570.     begin
  21571.         RAISERROR(14043, 16, -1, '@lineage')
  21572.         return (1)
  21573.     end
  21574.  
  21575.     /*
  21576.     ** Check to see if current publication has permission
  21577.     */
  21578.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick = @tablenick, @pubid = @pubid
  21579.     if @retcode<>0 or @@ERROR<>0 return (1)
  21580.     
  21581.     if (@type=1 or @type=5 or @type=6)
  21582.     begin
  21583.         if @type = 5
  21584.         begin
  21585.             set @reason = formatmessage(20563) -- Out of partial range
  21586.             set @lineage = 0x00
  21587.         end
  21588.         else if @type = 6
  21589.         begin
  21590.             set @reason = formatmessage(20564) -- Deleted by system (e.g., to cope with dup key)
  21591.         end
  21592.         else
  21593.         begin
  21594.             set @reason = formatmessage(20562) -- Deleted by user
  21595.         end
  21596.         -- update or insert dbo.MSmerge_tombstone
  21597.         update dbo.MSmerge_tombstone set generation = @generation, lineage = @lineage, type = @type, reason = @reason
  21598.             where tablenick = @tablenick and rowguid = @rowguid
  21599.  
  21600.         if (@@rowcount = 0)
  21601.         begin
  21602.             insert into dbo.MSmerge_tombstone (rowguid, tablenick, type, generation, lineage, reason)
  21603.                 values (@rowguid, @tablenick, @type, @generation, @lineage, @reason)
  21604.  
  21605.             delete from dbo.MSmerge_contents where tablenick = @tablenick and rowguid = @rowguid
  21606.         end
  21607.     end
  21608.     else
  21609.     begin
  21610.  
  21611.         if not exists (select rowguid from dbo.MSmerge_contents where tablenick = @tablenick and rowguid = @rowguid)
  21612.         begin
  21613.             insert into dbo.MSmerge_contents (rowguid, tablenick, generation, lineage, colv1)
  21614.                 values (@rowguid, @tablenick, @generation, @lineage, @colv)
  21615.             delete from dbo.MSmerge_tombstone where tablenick = @tablenick and rowguid = @rowguid
  21616.             select @tombstone_rows_deleted = @@rowcount
  21617.         end
  21618.         else
  21619.         begin
  21620.             -- update or insert to MSmerge_contents
  21621.             -- The following updates the generation to passed in value only if the 
  21622.             -- filter columns have not changed.
  21623.  
  21624.             -- If filter values have changed, update the generation to gen_cur for article - 
  21625.             -- This will allow a subsequent download to cleanup rows that don't belong at subscriber
  21626.             
  21627.             update dbo.MSmerge_contents 
  21628.             set generation = case when (isnull(partchangegen, -1) <> sma.gen_cur and isnull(joinchangegen, -1) <> sma.gen_cur) then @generation else sma.gen_cur end, 
  21629.                 lineage = @lineage, 
  21630.                 colv1 = case when datalength(@colv) < datalength(colv1) then colv1 else @colv end
  21631.             from dbo.MSmerge_contents mc, (select top 1 nickname, gen_cur = isnull(gen_cur, 0) from sysmergearticles where nickname = @tablenick) as sma
  21632.             where tablenick = @tablenick 
  21633.             and rowguid = @rowguid
  21634.             and mc.tablenick = sma.nickname
  21635.  
  21636.             if (@@rowcount = 0)
  21637.             begin
  21638.                 insert into dbo.MSmerge_contents (rowguid, tablenick, generation, lineage, colv1)
  21639.                     values (@rowguid, @tablenick, @generation, @lineage, @colv)
  21640.                 delete from dbo.MSmerge_tombstone where tablenick = @tablenick and rowguid = @rowguid
  21641.                 select @tombstone_rows_deleted = @@rowcount
  21642.             end
  21643.         end
  21644.     end
  21645.  
  21646.     IF @@ERROR<>0 return (1) 
  21647.     return (0)
  21648. go
  21649. exec dbo.sp_MS_marksystemobject sp_MSsetrowmetadata
  21650. go
  21651. grant exec on dbo.sp_MSsetrowmetadata to public
  21652. go
  21653.  
  21654. raiserror('Creating procedure sp_MSinsertgenhistory', 0,1)
  21655. GO
  21656.  
  21657. CREATE PROCEDURE sp_MSinsertgenhistory
  21658.     (@guidsrc uniqueidentifier,
  21659.      @gen int output,
  21660.      @pubid uniqueidentifier,
  21661.      @pubid_ins uniqueidentifier = NULL,
  21662.      @nicknames varbinary(1000) = 0x0,
  21663.      @artnick int = NULL
  21664.     )
  21665. as
  21666.     /*
  21667.     ** Check to see if current publication has permission
  21668.     */
  21669.     declare @retcode int, @mynickname int, @newnicks varbinary(1000), @dt datetime
  21670.     
  21671.     if ({ fn ISPALUSER(@pubid) } <> 1)
  21672.     begin    
  21673.         RAISERROR (14126, 11, -1)
  21674.         return (1)
  21675.     end
  21676.     
  21677.     if (@guidsrc is null)
  21678.     begin
  21679.         RAISERROR(14043, 16, -1, '@guidsrc')
  21680.         return (1)
  21681.     end
  21682.     
  21683.     -- having the login time in dbo.MSmerge_genhistory allows to associate the row with the merge process that inserted the row
  21684.     select @dt= login_time from master.dbo.sysprocesses where spid = @@spid
  21685.  
  21686.     -- Check for older in process generation
  21687.  
  21688.     select @gen = max(generation) from dbo.MSmerge_genhistory where guidsrc = @guidsrc
  21689.     if @gen is not null
  21690.     begin
  21691.         -- this generation was interrupted at a previous merge
  21692.         -- next statement makes sure that gen does no longer look interrupted to another process
  21693.         update dbo.MSmerge_genhistory set coldate= @dt where guidsrc = @guidsrc
  21694.  
  21695.         -- if @@rowcount = 0, another process removed the interrupted gen just before the previous update statement
  21696.         if @@rowcount > 0
  21697.         begin
  21698.             return (0)
  21699.         end
  21700.     end
  21701.  
  21702.     exec dbo.sp_MSgetreplnick @nickname = @mynickname out
  21703.     if @@ERROR<>0 return (1)
  21704.  
  21705.     -- Append guard byte if it is needed
  21706.     if @nicknames = 0x0 and (@mynickname % 256 = 0)
  21707.         set @newnicks = convert(binary(4), @mynickname) + 0x01
  21708.     else
  21709.         set @newnicks = convert(binary(4), @mynickname) + @nicknames
  21710.         
  21711.     begin tran
  21712.     save tran sp_MSinsertgenhistory
  21713.     
  21714.     select @gen = COALESCE(1 + max(generation), 1) from dbo.MSmerge_genhistory (updlock)
  21715.  
  21716.     if (@gen is NULL)
  21717.         select @gen = 1
  21718.     
  21719.     insert into dbo.MSmerge_genhistory (guidsrc, pubid, guidlocal, generation, art_nick, nicknames, coldate) 
  21720.         values (@guidsrc, @pubid_ins, '00000000-0000-0000-0000-000000000000', @gen, @artnick, @newnicks, @dt)
  21721.  
  21722.     if @@error<>0 goto Failure
  21723.         
  21724.     commit tran
  21725.     return (0)
  21726. Failure:
  21727.     rollback tran sp_MSinsertgenhistory
  21728.     commit tran
  21729.     RAISERROR(15001, 16, -1, 'MSmerge_genhistory')
  21730.     return (1)
  21731. go
  21732. exec dbo.sp_MS_marksystemobject sp_MSinsertgenhistory
  21733. go
  21734. grant exec on dbo.sp_MSinsertgenhistory to public
  21735.  
  21736. raiserror('Creating procedure sp_MSupdategenhistory', 0,1)
  21737. GO
  21738.  
  21739. CREATE PROCEDURE sp_MSupdategenhistory
  21740.     (@guidsrc uniqueidentifier, @pubid uniqueidentifier, @gen int, @art_nick int = NULL)
  21741. as
  21742.     declare @guidlocal uniqueidentifier
  21743.     
  21744.     /*
  21745.     ** Check to see if current publication has permission
  21746.     */
  21747.     declare @retcode int
  21748.  
  21749.     if ({ fn ISPALUSER(@pubid) } <> 1)
  21750.     begin    
  21751.         RAISERROR (14126, 11, -1)
  21752.         return (1)
  21753.     end
  21754.     
  21755.     if (@guidsrc is null)
  21756.     begin
  21757.         RAISERROR(14043, 16, -1, '@guidsrc')
  21758.         return (1)
  21759.     end
  21760.         
  21761.     if @art_nick = 0 set @art_nick = NULL
  21762.     
  21763.     set @guidlocal = newid()
  21764.     begin tran
  21765.     save tran sp_MSupdategenhistory
  21766.     if exists (select * from dbo.MSmerge_genhistory where guidsrc = @guidsrc and generation < @gen)
  21767.     begin
  21768.         create table #gentable (generation int)
  21769.  
  21770.         insert into #gentable select generation from dbo.MSmerge_genhistory where guidsrc = @guidsrc and generation < @gen
  21771.  
  21772.         update mc set mc.generation= @gen from dbo.MSmerge_contents as mc inner join #gentable as g 
  21773.             on (mc.generation=g.generation) 
  21774.         if @@ERROR <> 0 goto FAILURE
  21775.  
  21776.         update mt set mt.generation= @gen from dbo.MSmerge_tombstone as mt inner join #gentable as g 
  21777.             on (mt.generation=g.generation) 
  21778.         if @@ERROR <> 0 goto FAILURE
  21779.         
  21780.         declare @cmd nvarchar(200)
  21781.         declare @bi_objid int
  21782.         set @bi_objid= (select top 1 before_image_objid from sysmergearticles where nickname = @art_nick)
  21783.         if @bi_objid is not null
  21784.         begin
  21785.             set @cmd= 'update bi set bi.generation= @gen from dbo.' + object_name(@bi_objid) + ' as bi inner join #gentable as g
  21786.                 on (bi.generation = g.generation)'
  21787.             exec dbo.sp_executesql @cmd, N'@gen int', @gen= @gen
  21788.             if @@ERROR <> 0 goto FAILURE
  21789.         end
  21790.  
  21791.         delete from dbo.MSmerge_genhistory where guidsrc = @guidsrc and generation < @gen
  21792.         
  21793.         if @@ERROR <> 0 goto FAILURE
  21794.  
  21795.         drop table #gentable
  21796.     end
  21797.     if exists (select * from dbo.MSmerge_genhistory where guidsrc = @guidsrc)
  21798.         update dbo.MSmerge_genhistory set   guidlocal= @guidlocal, 
  21799.                                             art_nick = case when isnull(@art_nick,0) <> 0 then @art_nick else art_nick end, 
  21800.                                             coldate= getdate() 
  21801.                                             where generation = @gen -- and guidsrc = @guidsrc 
  21802.  
  21803.     else
  21804.     begin
  21805.         declare @mynickname int
  21806.         declare @nickbin varbinary(255)
  21807.  
  21808.         exec dbo.sp_MSgetreplnick @nickname = @mynickname out
  21809.         if @@ERROR<>0 goto FAILURE
  21810.  
  21811.         -- Append guard byte if it is needed
  21812.         if @mynickname % 256 = 0
  21813.             set @nickbin  = convert(binary(4), @mynickname) + 0x01
  21814.         else
  21815.             set @nickbin  = convert(binary(4), @mynickname)
  21816.  
  21817.         insert into dbo.MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) values
  21818.             (@guidsrc, @guidlocal, @gen, @art_nick, @nickbin , getdate())
  21819.  
  21820.  
  21821.     end
  21822.  
  21823.     commit
  21824.  
  21825.     -- Now that we have closed a generation that was open, we might be ready to
  21826.     -- cleanup metadata or something like that.
  21827.     exec @retcode = sp_MSquiescecheck                    
  21828.     
  21829.     return (0)
  21830.     
  21831. FAILURE:
  21832.     rollback tran sp_MSupdategenhistory
  21833.     commit tran
  21834.     return(1)
  21835. go
  21836. exec dbo.sp_MS_marksystemobject sp_MSupdategenhistory
  21837. go
  21838. grant exec on dbo.sp_MSupdategenhistory to public
  21839. go
  21840.  
  21841. raiserror('Creating procedure sp_MSlocalizeinterruptedgenerations', 0,1)
  21842. GO
  21843.  
  21844. CREATE PROCEDURE sp_MSlocalizeinterruptedgenerations @localize_zeroartnick_generations bit=0
  21845. -- this proc loops over interrupted generations 
  21846. -- and transfers those changes that arrived before the interrupt to a new local generation
  21847. as
  21848. begin
  21849.  
  21850.     declare @new_guidsrc uniqueidentifier
  21851.  
  21852.     if @localize_zeroartnick_generations = 0
  21853.         update dbo.MSmerge_genhistory set @new_guidsrc = guidsrc = newid(), guidlocal = @new_guidsrc, coldate = getdate()
  21854.         where guidlocal = '00000000-0000-0000-0000-000000000000'  -- incomplete gen
  21855.         and generation not in (select gen_cur from sysmergearticles)  -- not a local incomplete gen
  21856.         and coldate not in (select login_time from master..sysprocesses)  -- not a gen that currently receives replica updates from another db
  21857.         and isnull(art_nick, 0) <> 0        -- we don't localize generations with art_nick = 0 or NULL.
  21858.     else
  21859.         update dbo.MSmerge_genhistory set @new_guidsrc = guidsrc = newid(), guidlocal = @new_guidsrc, coldate = getdate()
  21860.         where guidlocal = '00000000-0000-0000-0000-000000000000'  -- incomplete gen
  21861.         and generation not in (select gen_cur from sysmergearticles)  -- not a local incomplete gen
  21862.         and coldate not in (select login_time from master..sysprocesses)  -- not a gen that currently receives replica updates from another db
  21863.     
  21864.     if @@error <> 0
  21865.         return 1
  21866.     else
  21867.         return 0
  21868. end
  21869. go
  21870. exec dbo.sp_MS_marksystemobject sp_MSlocalizeinterruptedgenerations
  21871. go
  21872.  
  21873. raiserror('Creating procedure sp_MSenumschemachange', 0,1)
  21874. GO
  21875.  
  21876. CREATE PROCEDURE sp_MSenumschemachange(
  21877.     @pubid                  uniqueidentifier,
  21878.     @schemaversion          int,
  21879.     @compatibility_level int = 7000000,
  21880.     @AlterTableOnly         bit = 0
  21881.     )
  21882. as    
  21883.     set nocount on
  21884.     declare @retcode int
  21885.  
  21886.     select @retcode = 0
  21887.  
  21888.     if ({ fn ISPALUSER(@pubid) } <> 1)
  21889.     begin    
  21890.         RAISERROR (14126, 11, -1)
  21891.         return (1)
  21892.     end
  21893.  
  21894.     -- Delegate call to the appropriate sp that
  21895.     -- handles the given compatibility-level  
  21896.     if @compatibility_level >= 8000500 -- this value stands for 80sp3 
  21897.     begin
  21898.         exec @retcode = sp_MSenumschemachange_80sp3 @pubid = @pubid, 
  21899.                                                     @AlterTableOnly = @AlterTableOnly,
  21900.                                                     @schemaversion = @schemaversion
  21901.  
  21902.     end
  21903.     else if @compatibility_level > 7000200 --this value standing for 70SP2
  21904.     begin
  21905.         exec @retcode = sp_MSenumschemachange_80 @pubid = @pubid, 
  21906.                                                  @AlterTableOnly = @AlterTableOnly,
  21907.                                                  @schemaversion = @schemaversion
  21908.     end
  21909.     else
  21910.     begin
  21911.         exec @retcode = sp_MSenumschemachange_70 @pubid = @pubid,
  21912.                                                  @AlterTableOnly = @AlterTableOnly,
  21913.                                                  @schemaversion = @schemaversion,
  21914.                                                  @compatibility_level=@compatibility_level
  21915.     end
  21916.  
  21917.     return @retcode
  21918. go
  21919. exec dbo.sp_MS_marksystemobject sp_MSenumschemachange
  21920. go
  21921. grant exec on dbo.sp_MSenumschemachange to public
  21922. go
  21923.  
  21924. raiserror('Creating procedure sp_MSenumschemachange_70', 0,1)
  21925. GO
  21926.  
  21927. CREATE PROCEDURE sp_MSenumschemachange_70(
  21928.     @pubid                         uniqueidentifier,
  21929.     @AlterTableOnly                int,
  21930.     @schemaversion                 int,
  21931.     @compatibility_level         int
  21932.     )
  21933. as
  21934.  
  21935.     /*
  21936.     ** To public
  21937.     */
  21938.     
  21939.     if (@schemaversion is null)
  21940.         begin
  21941.         RAISERROR(14043, 16, -1, '@schemaversion')
  21942.         return (1)
  21943.         end
  21944.  
  21945.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  21946.         begin
  21947.         RAISERROR(20054 , 16, -1)
  21948.         return (1)
  21949.         end
  21950.  
  21951.     create table #temp_table_sp_MSenumschemachange_70
  21952.         (pubid uniqueidentifier NULL, 
  21953.          artid uniqueidentifier NULL,
  21954.          schemaversion int NULL,
  21955.          schemaguid uniqueidentifier NULL,
  21956.          schematype int NULL,
  21957.          schematext nvarchar(2000) collate database_default null)
  21958.  
  21959.     /* handle the case of reinitall */
  21960.     if exists (select pubid from sysmergeschemachange where schemaversion > @schemaversion 
  21961.              and pubid = @pubid and schematype = 12)
  21962.         select @schemaversion = 0
  21963.  
  21964.     /*
  21965.     ** For 70 RTM and SP1, we want to filter out type 9 (retention propagation) and 16 (metadata cleanup)
  21966.     ** and 5 ( last rec generation ) and 6 (last sent generation)
  21967.     ** which they do not support. SP2 subscriber will be passing in 7000200, which gets understands
  21968.     ** these schema types
  21969.     */
  21970.     insert into #temp_table_sp_MSenumschemachange_70
  21971.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  21972.           from sysmergeschemachange where schemaversion > @schemaversion 
  21973.                  and pubid = @pubid
  21974.                 and ((@compatibility_level=7000000 and schematype in (-1, 1, 2, 3, 4, 7, 8, 10, 15, 20))
  21975.                     or (@compatibility_level=7000200 and 
  21976.                         ((schematype in (-1, 1, 2, 3, 4, 7, 8, 9, 10, 12, 15, 16, 20,66)) 
  21977.                             or schematype in (5, 6) and @schemaversion = 0)))
  21978.         order by schemaversion         
  21979.         
  21980.     /* for SP2 downlevel subscribers who do not understand type 12 (reinit-all) at provider level, but do
  21981.     ** at reconcile level, change it to type = 7 (directory) to be no-op.
  21982.     */
  21983.     if @compatibility_level=7000200
  21984.         update #temp_table_sp_MSenumschemachange_70 set schematype=7 where schematype = 12
  21985.  
  21986.     select  * from #temp_table_sp_MSenumschemachange_70
  21987.     drop table #temp_table_sp_MSenumschemachange_70
  21988.     
  21989.     return (0)
  21990. go
  21991. exec dbo.sp_MS_marksystemobject sp_MSenumschemachange_70
  21992. go
  21993.  
  21994.  
  21995. raiserror('Creating procedure sp_MSenumschemachange_80', 0,1)
  21996. GO
  21997.  
  21998. CREATE PROCEDURE sp_MSenumschemachange_80(
  21999.     @pubid                    uniqueidentifier,
  22000.     @AlterTableOnly                    int,
  22001.     @schemaversion            int
  22002.     )
  22003. as
  22004.     set nocount on
  22005.     /*
  22006.     ** To public
  22007.     */
  22008.     declare    @alter_table_type        int
  22009.     declare @reinit_all_type         int
  22010.     declare @reinit_all_upload_type int
  22011.     declare @schemaversion_of_snapshottrailer int
  22012.     
  22013.     select @reinit_all_type = 12
  22014.     select @alter_table_type = 11
  22015.     select @reinit_all_upload_type = 14
  22016.     
  22017.     if (@schemaversion is null)
  22018.         begin
  22019.         RAISERROR(14043, 16, -1, '@schemaversion')
  22020.         return (1)
  22021.         end
  22022.  
  22023.         --    @schema_needed = 0 - only send back reinitall command, if any 
  22024.         --  @schema_needed = 1 - normal enumeration
  22025.         --  @schema_needed = 2 - only send back alter-table command, if any
  22026.         --  @schema_needed = 3 - only send back reinitall-with-upload command, if any.
  22027.  
  22028.     if (@AlterTableOnly = 1)
  22029.         begin
  22030.             select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22031.                 from sysmergeschemachange where pubid=@pubid and schemaversion > @schemaversion and schematype = @alter_table_type
  22032.             return (0)            
  22033.         end
  22034.         
  22035.     if exists (select * from sysmergeschemachange where 
  22036.         pubid=@pubid and ((schemaversion > @schemaversion and schematype = @reinit_all_type)
  22037.         or (schemaversion > @schemaversion and schematype = @reinit_all_upload_type)))
  22038.         begin
  22039.             select @schemaversion=0
  22040.         end
  22041.  
  22042.     -- If subscriber missed a preparecleanup and a completecleanup they must be reinitialized
  22043.     
  22044.     if exists (select * from sysmergeschemachange where 
  22045.         pubid=@pubid and schemaversion > @schemaversion and schematype = 17) and
  22046.         exists (select * from sysmergeschemachange where 
  22047.         pubid=@pubid and schemaversion > @schemaversion and schematype = 19)         
  22048.         begin
  22049.             set @schemaversion=0
  22050.         end
  22051.         
  22052.     if (@schemaversion > 0) 
  22053.     begin
  22054.         -- Subscriber has already received the snapshot so filter out 
  22055.         -- the pre/post-snapshot commands. 
  22056.         -- Also filter out the schemtypes for the setlastsentgen (5) and setlastrecgen (6)
  22057.         -- This ensures that the subscriber does not apply these schema changes when 
  22058.         -- it applies incremental schema - ie the perf optimization that is implemented 
  22059.         -- by setting last sent/rec generation should be done only for brand new subscriptions.
  22060.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22061.           from sysmergeschemachange where schemaversion > @schemaversion  
  22062.            and pubid = @pubid
  22063.            and schematype not in (40, 45, 50, 51, 52, 53, 54, 55, 56, 57, 58, 25, 5, 6)
  22064.       order by schemaversion 
  22065.     end
  22066.     Else 
  22067.     begin
  22068.         -- Subscriber requires a snapshot, so carefully sequence the 
  22069.         -- pre/post-snapshot commands around the snapshot boundary
  22070.  
  22071.         create table #schemachanges 
  22072.         (   
  22073.             pubid           uniqueidentifier  NOT NULL,
  22074.             artid           uniqueidentifier  NULL,
  22075.             schemaversion   int               NOT NULL,
  22076.             schemaguid      uniqueidentifier  NOT NULL,
  22077.             schematype      int               NOT NULL,
  22078.             schematext      nvarchar(2000)    collate database_default not null,
  22079.             seqno           int identity      NOT NULL
  22080.         )
  22081.         
  22082.         truncate table #schemachanges
  22083.         -- Insert snapshot header 
  22084.  
  22085.         -- Header begins
  22086.         insert into #schemachanges
  22087.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22088.           from sysmergeschemachange where schemaversion > @schemaversion 
  22089.            and pubid = @pubid
  22090.            and schematype = 50
  22091.  
  22092.         -- Header content
  22093.         insert into #schemachanges
  22094.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22095.           from sysmergeschemachange where schemaversion > @schemaversion 
  22096.            and pubid = @pubid
  22097.            and schematype in (25, 53, 54, 55, 56, 57, 58) 
  22098.         order by schemaversion 
  22099.  
  22100.         -- Header ends
  22101.         insert into #schemachanges
  22102.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22103.           from sysmergeschemachange where schemaversion > @schemaversion 
  22104.            and pubid = @pubid
  22105.            and schematype = 51 
  22106.  
  22107.         -- End of snapshot header 
  22108.         -- Insert pre command
  22109.         insert into #schemachanges
  22110.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22111.           from sysmergeschemachange where schemaversion > @schemaversion 
  22112.            and pubid = @pubid
  22113.            and schematype = 40 
  22114.  
  22115.         -- Exclude pre-post, but include snapshot only commands
  22116.         insert into #schemachanges
  22117.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22118.           from sysmergeschemachange where schemaversion > @schemaversion 
  22119.            and pubid = @pubid
  22120.            and schematype in (2, 3, 4, 20, 7, 60, 61, 62, 63, 64)
  22121.          order by schemaversion 
  22122.  
  22123.         -- Dynamic BCP commands
  22124.         insert into #schemachanges
  22125.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22126.           from sysmergeschemachange where schemaversion > @schemaversion 
  22127.            and pubid = @pubid
  22128.            and schematype in (131, 132)
  22129.          order by schemaversion         
  22130.         
  22131.         -- DRI/Trg/XPROP
  22132.         insert into #schemachanges
  22133.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22134.           from sysmergeschemachange where schemaversion > @schemaversion 
  22135.            and pubid = @pubid
  22136.            and schematype in (10, 15, 65)
  22137.          order by schemaversion         
  22138.  
  22139.         -- Insert post command
  22140.         insert into #schemachanges
  22141.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22142.           from sysmergeschemachange where schemaversion > @schemaversion 
  22143.            and pubid = @pubid
  22144.            and schematype = 45 
  22145.  
  22146.         -- Insert snapshot trailer
  22147.         insert into #schemachanges
  22148.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22149.           from sysmergeschemachange where schemaversion > @schemaversion 
  22150.            and pubid = @pubid
  22151.            and schematype = 52 
  22152.         
  22153.         -- Insert other schema changes
  22154.         insert into #schemachanges 
  22155.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22156.           from sysmergeschemachange where schemaversion > @schemaversion 
  22157.            and schematype not in (2, 3, 4, 10, 15, 20, 7, 40, 45, 60)
  22158.            and schematype not in (61, 62, 63, 64, 65)
  22159.            and schematype not in (25, 50, 51, 52, 53, 54, 55, 56, 57, 58)
  22160.            and schematype not in (131, 132) -- dynamic bcp commands
  22161.            and schematype not in (46, 11, 13) -- The on-demand script and schema replication commands should not be enumerated unless 
  22162.                                       -- we have made sure that it was posted after the current snapshot.
  22163.            and pubid = @pubid
  22164.          order by schemaversion                   
  22165.  
  22166.         -- get the schemaversion of the snapshot trailer row
  22167.         select @schemaversion_of_snapshottrailer = schemaversion from sysmergeschemachange 
  22168.             where schemaversion > @schemaversion 
  22169.             and pubid = @pubid
  22170.             and schematype = 52 
  22171.  
  22172.         if (@schemaversion_of_snapshottrailer is not null)
  22173.         begin
  22174.             -- insert schema changes for on-demand script and schema replication commands which have schemaversion greater than
  22175.             -- schemaversion of the snapshot trailer row
  22176.             insert into #schemachanges 
  22177.             select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22178.             from sysmergeschemachange where schemaversion > @schemaversion_of_snapshottrailer 
  22179.             and schematype in (46, 11, 13) -- The on-demand script and schema replication commands only.
  22180.             and pubid = @pubid
  22181.             order by schemaversion
  22182.         end
  22183.             
  22184.         declare @endofsnapshot int
  22185.         select @endofsnapshot = min(seqno) from #schemachanges 
  22186.         where schematype = 52
  22187.         delete #schemachanges where seqno > @endofsnapshot
  22188.             and (schematype in (2, 3, 4, 10, 15, 20, 7, 40, 45, 65) or 
  22189.             schematype in (25, 50, 51, 52, 53, 54, 55, 56, 57, 58))
  22190.  
  22191.         --only list the last reinitall command 
  22192.         delete schemachanges1 from #schemachanges schemachanges1,#schemachanges schemachanges2 
  22193.             where schemachanges1.pubid=@pubid and schemachanges1.schematype=12 and 
  22194.                   schemachanges2.pubid=@pubid and schemachanges2.schematype=12 and
  22195.                   schemachanges1.schemaversion<schemachanges2.schemaversion
  22196.         
  22197.         --only list the last reinitall-with-upload command 
  22198.         delete schemachanges1 from #schemachanges schemachanges1, #schemachanges schemachanges2 
  22199.             where schemachanges1.pubid=@pubid and schemachanges1.schematype=14 and 
  22200.                   schemachanges2.pubid=@pubid and schemachanges2.schematype=14 and
  22201.                   schemachanges1.schemaversion<schemachanges2.schemaversion
  22202.  
  22203.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22204.           from #schemachanges order by seqno
  22205.  
  22206.         drop table #schemachanges
  22207.     end
  22208.  
  22209.     return (0)
  22210. go
  22211. exec dbo.sp_MS_marksystemobject sp_MSenumschemachange_80
  22212. go
  22213.  
  22214. raiserror('Creating procedure sp_MSenumschemachange_80sp3', 0,1)
  22215. GO
  22216.  
  22217. CREATE PROCEDURE sp_MSenumschemachange_80sp3(
  22218.     @pubid                    uniqueidentifier,
  22219.     @AlterTableOnly                    int,
  22220.     @schemaversion            int
  22221.     )
  22222. as
  22223.     set nocount on
  22224.     /*
  22225.     ** To public
  22226.     */
  22227.     declare    @alter_table_type        int
  22228.     declare @reinit_all_type         int
  22229.     declare @reinit_all_upload_type int
  22230.     declare @schemaversion_of_snapshottrailer int
  22231.     
  22232.     select @reinit_all_type = 12
  22233.     select @alter_table_type = 11
  22234.     select @reinit_all_upload_type = 14
  22235.     
  22236.     if (@schemaversion is null)
  22237.         begin
  22238.         RAISERROR(14043, 16, -1, '@schemaversion')
  22239.         return (1)
  22240.         end
  22241.  
  22242.         --    @schema_needed = 0 - only send back reinitall command, if any 
  22243.         --  @schema_needed = 1 - normal enumeration
  22244.         --  @schema_needed = 2 - only send back alter-table command, if any
  22245.         --  @schema_needed = 3 - only send back reinitall-with-upload command, if any.
  22246.  
  22247.     if (@AlterTableOnly = 1)
  22248.         begin
  22249.             select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22250.                 from sysmergeschemachange where pubid=@pubid and schemaversion > @schemaversion and schematype = @alter_table_type
  22251.             return (0)            
  22252.         end
  22253.         
  22254.     if exists (select * from sysmergeschemachange where 
  22255.         pubid=@pubid and ((schemaversion > @schemaversion and schematype = @reinit_all_type)
  22256.         or (schemaversion > @schemaversion and schematype = @reinit_all_upload_type)))
  22257.         begin
  22258.             select @schemaversion=0
  22259.         end
  22260.  
  22261.     -- If subscriber missed a preparecleanup and a completecleanup they must be reinitialized
  22262.     
  22263.     if exists (select * from sysmergeschemachange where 
  22264.         pubid=@pubid and schemaversion > @schemaversion and schematype = 17) and
  22265.         exists (select * from sysmergeschemachange where 
  22266.         pubid=@pubid and schemaversion > @schemaversion and schematype = 19)         
  22267.         begin
  22268.             set @schemaversion=0
  22269.         end
  22270.         
  22271.     if (@schemaversion > 0) 
  22272.     begin
  22273.         -- Subscriber has already received the snapshot so filter out 
  22274.         -- the pre/post-snapshot commands. 
  22275.         -- If @schemaversion > 0, there are two main cases that we need to 
  22276.         -- consider: 
  22277.         -- i) There are incremental article commands such as bcp/schema 
  22278.         --    commands that need to be applied within a "fake" snapshot 
  22279.         --    boundary
  22280.         -- ii) There is no incremental article commands, schema changes can be
  22281.         --     applied "normally"
  22282.         declare @min_incremental_schemaversion int
  22283.         declare @max_incremental_schemaversion int
  22284.  
  22285.         select @min_incremental_schemaversion = null
  22286.  
  22287.         select @min_incremental_schemaversion = min(schemaversion),         
  22288.                @max_incremental_schemaversion = max(schemaversion)
  22289.           from dbo.sysmergeschemachange where schemaversion > @schemaversion
  22290.            and pubid = @pubid 
  22291.            -- normal snapshot commands excluding pre/post snapshot commands
  22292.            -- and system tables commands
  22293.            and schematype in (2, 3, 4, 61, 62, 63, 64, 131, 132, 10, 15, 65)
  22294.  
  22295.         if @min_incremental_schemaversion is not null
  22296.         begin
  22297.             
  22298.             -- case i), we have incrementally added articles
  22299.  
  22300.             -- Need to save off the schemaguid of the max incremental change
  22301.             -- for labelling the trailer. This is to prevent the schema 
  22302.             -- validation logic from raising false alarm saying that the
  22303.             -- publisher is restored from a backup
  22304.             declare @max_incremental_schemaguid uniqueidentifier            
  22305.             select @max_incremental_schemaguid = schemaguid 
  22306.               from dbo.sysmergeschemachange 
  22307.              where schemaversion = @max_incremental_schemaversion
  22308.                and pubid = @pubid               
  22309.                 
  22310.             declare @incremental_schematype_bit int
  22311.             select @incremental_schematype_bit = 1024
  22312.  
  22313.             declare @incremental_schemachanges table
  22314.             (   
  22315.                 pubid           uniqueidentifier  NOT NULL,
  22316.                 artid           uniqueidentifier  NULL,
  22317.                 schemaversion   int               NOT NULL,
  22318.                 schemaguid      uniqueidentifier  NOT NULL,
  22319.                 schematype      int               NOT NULL,
  22320.                 schematext      nvarchar(2000)    collate database_default not null,
  22321.                 seqno           int identity      NOT NULL
  22322.             )
  22323.             if @@error <> 0 return 1
  22324.             
  22325.             -- Insert every thing before @min_incremental_schemaversion but
  22326.             -- after @schemaversion
  22327.             -- Note: Excluded list should include all snapshot header, trailer commands
  22328.  
  22329.             insert into @incremental_schemachanges 
  22330.             select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22331.               from dbo.sysmergeschemachange where schemaversion > @schemaversion
  22332.                and schemaversion < @min_incremental_schemaversion 
  22333.                and pubid = @pubid
  22334.                and schematype not in (40, 45, 50, 51, 52, 53, 54, 55, 56, 57, 58, 25, 5, 6, 71, 80, 81, 82, 83)
  22335.             order by schemaversion 
  22336.             if @@error <> 0 return 1
  22337.  
  22338.             -- Incremental snapshot header
  22339.             -- Header begins
  22340.             insert into @incremental_schemachanges
  22341.             select pubid, artid, @min_incremental_schemaversion, schemaguid, schematype | @incremental_schematype_bit, schematext 
  22342.               from dbo.sysmergeschemachange
  22343.              where pubid = @pubid
  22344.                and schematype = 50
  22345.             if @@error <> 0 return 1
  22346.  
  22347.             -- Header content
  22348.             insert into @incremental_schemachanges
  22349.             select pubid, artid, @min_incremental_schemaversion, schemaguid, schematype | @incremental_schematype_bit, schematext 
  22350.               from dbo.sysmergeschemachange
  22351.              where pubid = @pubid
  22352.                and schematype in (25, 53, 54, 55, 56, 57, 58)
  22353. --            order by schemaversion
  22354.             if @@error <> 0 return 1
  22355.  
  22356.             -- Header ends
  22357.             insert into @incremental_schemachanges
  22358.             select pubid, artid, @min_incremental_schemaversion, schemaguid, schematype | @incremental_schematype_bit, schematext
  22359.              from dbo.sysmergeschemachange
  22360.             where pubid = @pubid
  22361.               and schematype = 51
  22362.             if @@error <> 0 return 1
  22363.  
  22364.             -- Add everything between max and min and filter out things
  22365.             -- we didn't want before in the normal case
  22366.             -- Note: Excluded list should include all snapshot header, trailer commands
  22367.             insert into @incremental_schemachanges
  22368.             select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22369.               from dbo.sysmergeschemachange where schemaversion >= @min_incremental_schemaversion
  22370.                and schemaversion <= @max_incremental_schemaversion
  22371.                and pubid = @pubid
  22372.                and schematype not in (40, 45, 50, 51, 52, 53, 54, 55, 56, 57, 58, 25, 5, 6, 71, 80, 81, 82, 83)
  22373.             order by schemaversion 
  22374.             if @@error <> 0 return 1
  22375.  
  22376.             -- Incremental snapshot trailer
  22377.             insert into @incremental_schemachanges
  22378.             select pubid, artid, @max_incremental_schemaversion, @max_incremental_schemaguid, schematype | @incremental_schematype_bit, schematext
  22379.               from dbo.sysmergeschemachange 
  22380.              where pubid = @pubid
  22381.                and schematype = 52
  22382.             if @@error <> 0 return 1
  22383.  
  22384.             -- Add everything after the incremental article commands
  22385.             -- Note: Excluded list should include all snapshot header, trailer commands
  22386.             insert into @incremental_schemachanges
  22387.             select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22388.               from dbo.sysmergeschemachange where schemaversion > @max_incremental_schemaversion
  22389.                and pubid = @pubid 
  22390.                and schematype not in (40, 45, 50, 51, 52, 53, 54, 55, 56, 57, 58, 25, 5, 6, 71, 80, 81, 82, 83)
  22391.             order by schemaversion 
  22392.  
  22393.             -- Return the end result
  22394.             select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22395.               from @incremental_schemachanges order by seqno asc
  22396.         end
  22397.         else
  22398.         begin
  22399.             -- case ii)
  22400.             -- Also filter out the schemtypes for the setlastsentgen (5) and setlastrecgen (6)
  22401.             -- This ensures that the subscriber does not apply these schema changes when 
  22402.             -- it applies incremental schema - ie the perf optimization that is implemented 
  22403.             -- by setting last sent/rec generation should be done only for brand new subscriptions.
  22404.             select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22405.               from sysmergeschemachange where schemaversion > @schemaversion  
  22406.                and pubid = @pubid
  22407.                and schematype not in (40, 45, 50, 51, 52, 53, 54, 55, 56, 57, 58, 25, 5, 6, 71, 80, 81, 82, 83)
  22408.             order by schemaversion
  22409.         end 
  22410.     end
  22411.     Else 
  22412.     begin
  22413.         -- Subscriber requires a snapshot, so carefully sequence the 
  22414.         -- pre/post-snapshot commands around the snapshot boundary
  22415.  
  22416.         create table #schemachanges 
  22417.         (   
  22418.             pubid           uniqueidentifier  NOT NULL,
  22419.             artid           uniqueidentifier  NULL,
  22420.             schemaversion   int               NOT NULL,
  22421.             schemaguid      uniqueidentifier  NOT NULL,
  22422.             schematype      int               NOT NULL,
  22423.             schematext      nvarchar(2000)    collate database_default not null,
  22424.             seqno           int identity      NOT NULL
  22425.         )
  22426.         
  22427.         truncate table #schemachanges
  22428.         -- Insert snapshot header 
  22429.  
  22430.         -- Header begins
  22431.         insert into #schemachanges
  22432.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22433.           from sysmergeschemachange where schemaversion > @schemaversion 
  22434.            and pubid = @pubid
  22435.            and schematype = 50
  22436.  
  22437.         -- Header content
  22438.         insert into #schemachanges
  22439.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22440.           from sysmergeschemachange where schemaversion > @schemaversion 
  22441.            and pubid = @pubid
  22442.            and schematype in (25, 53, 54, 55, 56, 57, 58) 
  22443.         order by schemaversion 
  22444.  
  22445.         -- Header ends
  22446.         insert into #schemachanges
  22447.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22448.           from sysmergeschemachange where schemaversion > @schemaversion 
  22449.            and pubid = @pubid
  22450.            and schematype = 51 
  22451.  
  22452.         -- End of snapshot header 
  22453.         -- Insert pre command
  22454.         insert into #schemachanges
  22455.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22456.           from sysmergeschemachange where schemaversion > @schemaversion 
  22457.            and pubid = @pubid
  22458.            and schematype = 40 
  22459.  
  22460.         -- Exclude pre-post, but include snapshot only commands
  22461.         insert into #schemachanges
  22462.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22463.           from sysmergeschemachange where schemaversion > @schemaversion 
  22464.            and pubid = @pubid
  22465.            and schematype in (2, 3, 4, 20, 7, 60, 61, 62, 63, 64)
  22466.          order by schemaversion 
  22467.  
  22468.         -- Dynamic BCP commands
  22469.         insert into #schemachanges
  22470.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22471.           from sysmergeschemachange where schemaversion > @schemaversion 
  22472.            and pubid = @pubid
  22473.            and schematype in (131, 132)
  22474.          order by schemaversion         
  22475.         
  22476.         -- DRI/Trg/XPROP
  22477.         insert into #schemachanges
  22478.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22479.           from sysmergeschemachange where schemaversion > @schemaversion 
  22480.            and pubid = @pubid
  22481.            and schematype in (10, 15, 65)
  22482.          order by schemaversion         
  22483.  
  22484.         -- Insert post command
  22485.         insert into #schemachanges
  22486.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22487.           from sysmergeschemachange where schemaversion > @schemaversion 
  22488.            and pubid = @pubid
  22489.            and schematype = 45 
  22490.  
  22491.         -- Insert snapshot trailer
  22492.         insert into #schemachanges
  22493.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22494.           from sysmergeschemachange where schemaversion > @schemaversion 
  22495.            and pubid = @pubid
  22496.            and schematype = 52 
  22497.         
  22498.         -- Insert other schema changes
  22499.         insert into #schemachanges 
  22500.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22501.           from sysmergeschemachange where schemaversion > @schemaversion 
  22502.            and schematype not in (2, 3, 4, 10, 15, 20, 7, 40, 45, 60)
  22503.            and schematype not in (61, 62, 63, 64, 65)
  22504.            and schematype not in (25, 50, 51, 52, 53, 54, 55, 56, 57, 58)
  22505.            and schematype not in (131, 132) -- dynamic bcp commands
  22506.            and schematype not in (46, 11, 13) -- The on-demand script and schema replication commands should not be enumerated unless 
  22507.                                       -- we have made sure that it was posted after the current snapshot.
  22508.            and pubid = @pubid
  22509.          order by schemaversion                   
  22510.  
  22511.         -- get the schemaversion of the snapshot trailer row
  22512.         select @schemaversion_of_snapshottrailer = schemaversion from sysmergeschemachange 
  22513.             where schemaversion > @schemaversion 
  22514.             and pubid = @pubid
  22515.             and schematype = 52 
  22516.  
  22517.         if (@schemaversion_of_snapshottrailer is not null)
  22518.         begin
  22519.             -- insert schema changes for on-demand script and schema replication commands which have schemaversion greater than
  22520.             -- schemaversion of the snapshot trailer row
  22521.             insert into #schemachanges 
  22522.             select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22523.             from sysmergeschemachange where schemaversion > @schemaversion_of_snapshottrailer 
  22524.             and schematype in (46, 11, 13) -- The on-demand script and schema replication commands only.
  22525.             and pubid = @pubid
  22526.             order by schemaversion
  22527.         end
  22528.             
  22529.         declare @endofsnapshot int
  22530.         select @endofsnapshot = min(seqno) from #schemachanges 
  22531.         where schematype = 52
  22532.         delete #schemachanges where seqno > @endofsnapshot
  22533.             and (schematype in (2, 3, 4, 10, 15, 20, 7, 40, 45, 65) or 
  22534.             schematype in (25, 50, 51, 52, 53, 54, 55, 56, 57, 58))
  22535.  
  22536.         --only list the last reinitall command 
  22537.         delete schemachanges1 from #schemachanges schemachanges1,#schemachanges schemachanges2 
  22538.             where schemachanges1.pubid=@pubid and schemachanges1.schematype=12 and 
  22539.                   schemachanges2.pubid=@pubid and schemachanges2.schematype=12 and
  22540.                   schemachanges1.schemaversion<schemachanges2.schemaversion
  22541.         
  22542.         --only list the last reinitall-with-upload command 
  22543.         delete schemachanges1 from #schemachanges schemachanges1, #schemachanges schemachanges2 
  22544.             where schemachanges1.pubid=@pubid and schemachanges1.schematype=14 and 
  22545.                   schemachanges2.pubid=@pubid and schemachanges2.schematype=14 and
  22546.                   schemachanges1.schemaversion<schemachanges2.schemaversion
  22547.  
  22548.         select pubid, artid, schemaversion, schemaguid, schematype, schematext
  22549.           from #schemachanges order by seqno
  22550.  
  22551.         drop table #schemachanges
  22552.     end
  22553.  
  22554.     return (0)
  22555. go
  22556. exec dbo.sp_MS_marksystemobject sp_MSenumschemachange_80sp3
  22557. go
  22558.  
  22559. raiserror('Creating procedure sp_MSupdateschemachange', 0,1)
  22560. GO
  22561.  
  22562. CREATE PROCEDURE sp_MSupdateschemachange(
  22563.     @pubid            uniqueidentifier,
  22564.     @artid            uniqueidentifier = NULL, /* Can be NULL for directory commands */
  22565.     @schemaversion     int,
  22566.     @schemaguid        uniqueidentifier,
  22567.     @schematype        int,
  22568.     @schematext        nvarchar(2000)
  22569.     )
  22570. as
  22571.     /*
  22572.     ** Check to see if current publication has permission
  22573.     */
  22574.     declare @retcode int
  22575.  
  22576.     if ({ fn ISPALUSER(@pubid) } <> 1)
  22577.     begin    
  22578.         RAISERROR (14126, 11, -1)
  22579.         return (1)
  22580.     end
  22581.     
  22582.     /* Parameter validation */
  22583.     if (@schemaversion is null)
  22584.         begin
  22585.         RAISERROR(14043, 16, -1, '@schemaversion')
  22586.         return (1)
  22587.         end
  22588.  
  22589.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  22590.         begin
  22591.         RAISERROR(20054 , 16, -1)
  22592.         return (1)
  22593.         end
  22594.  
  22595.     update sysmergeschemachange set schematext = @schematext, schematype = @schematype
  22596.         where pubid = @pubid and schemaversion = @schemaversion
  22597.     if @@error <> 0        
  22598.         begin
  22599.             RAISERROR(20054 , 16, -1)
  22600.             return (1)
  22601.         end        
  22602.     return (0)
  22603. go
  22604. exec dbo.sp_MS_marksystemobject sp_MSupdateschemachange
  22605. go
  22606.  
  22607. raiserror('Creating procedure sp_MSremove_mergereplcommand', 0,1)
  22608. GO
  22609.  
  22610. /* Remove an article command of a specific tyep from sysmergeschemachange- Used by snapshot */
  22611. CREATE PROCEDURE sp_MSremove_mergereplcommand (
  22612.     @publication        sysname,
  22613.     @article            sysname,
  22614.     @schematype         int
  22615.     ) AS
  22616.     set nocount on
  22617.     declare @pubid                uniqueidentifier
  22618.     declare @artid                uniqueidentifier
  22619.     declare @retcode            int    
  22620.  
  22621.     exec @retcode=sp_MSreplcheck_publish
  22622.     if @retcode<>0 or @@ERROR<>0 return (1)
  22623.     
  22624.     if @publication IS NULL
  22625.     begin
  22626.         raiserror (14003, 16, -1)
  22627.         return (1)
  22628.     end
  22629.     
  22630.     if @article IS NULL
  22631.     begin
  22632.         raiserror (20045, 16, -1)
  22633.         return (1)
  22634.     end
  22635.  
  22636.     select @pubid = pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name()
  22637.     select @artid = artid FROM sysmergearticles WHERE name = @article and pubid=@pubid
  22638.  
  22639.     delete sysmergeschemachange where pubid = @pubid
  22640.                                   and artid = @artid
  22641.                              and schematype = @schematype
  22642.  
  22643. GO
  22644.  
  22645. exec dbo.sp_MS_marksystemobject sp_MSremove_mergereplcommand
  22646. go
  22647. grant exec on dbo.sp_MSremove_mergereplcommand to public
  22648. go
  22649.  
  22650. raiserror('Creating procedure sp_MSadd_mergereplcommand', 0,1)
  22651. GO
  22652.  
  22653. /* Add the replication command to the database - Used by snapshot */
  22654. CREATE PROCEDURE sp_MSadd_mergereplcommand (
  22655.     @publication        sysname,
  22656.     @article            sysname = NULL,
  22657.     @schematype            int,
  22658.     @schematext            nvarchar(2000)
  22659.     ) AS
  22660.     declare @schemaguid            uniqueidentifier
  22661.     declare @schemaversion         int
  22662.     declare @retcode             int
  22663.     declare @pubid                uniqueidentifier
  22664.     declare @artid                uniqueidentifier
  22665.     
  22666.     /*
  22667.     ** Publish permission check
  22668.     */
  22669.     exec @retcode=sp_MSreplcheck_publish
  22670.     if @retcode<>0 or @@ERROR<>0 return (1)
  22671.     
  22672.     if @publication IS NULL
  22673.         BEGIN
  22674.             RAISERROR (14003, 16, -1)
  22675.             RETURN (1)
  22676.         END
  22677.  
  22678.     select @pubid = pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name()
  22679.     select @artid = artid FROM sysmergeextendedarticlesview WHERE name = @article and pubid = @pubid
  22680.     /* 
  22681.     ** For certain system tables that are bcped out such as MSmerge_contents 
  22682.     ** and dbo.MSmerge_tombstone use the article name as sysobjects.name and get
  22683.     ** sysobjects.id as the artid
  22684.     */
  22685.     if (@artid IS NULL) AND (@schematype <> 7)
  22686.         begin
  22687.             declare @binguid binary(16)
  22688.             set @binguid = OBJECT_ID(@article)
  22689.             set @artid = convert(uniqueidentifier, @binguid)
  22690.         end
  22691.  
  22692.     if exists (select *    from sysmergeschemachange
  22693.             where pubid = @pubid 
  22694.             AND artid = @artid
  22695.             AND (schematype = @schematype or @schematype in (3,4) and schematype in (3,4)) )
  22696.         begin
  22697.             /* Select the existing schema guid */
  22698.             select @schemaversion = schemaversion, @schemaguid = schemaguid from sysmergeschemachange
  22699.                 where pubid = @pubid 
  22700.                 AND artid = @artid
  22701.                 AND (schematype = @schematype or @schematype in (3,4) and schematype in (3,4))
  22702.  
  22703.  
  22704.             /* For directory commands, delete the previous directory before the update */
  22705.             if (@schematype = 7)
  22706.                 begin
  22707.  
  22708.                     /* Remove the alternate directory command, pre/post 
  22709.                     ** commands, and snapshot header commands from the 
  22710.                     ** sysmergeschemachange table
  22711.                     */                     
  22712.                     delete sysmergeschemachange
  22713.                      where pubid = @pubid 
  22714.                        AND schematype in (25, 40, 45, 50, 51, 52, 53, 54, 55, 56, 57, 58)
  22715.  
  22716.                 end
  22717.  
  22718.             /*
  22719.             ** Update the schema change version
  22720.             */
  22721.             exec @retcode = dbo.sp_MSupdateschemachange @pubid, @artid, @schemaversion, 
  22722.                 @schemaguid, @schematype, @schematext
  22723.             if @@error <> 0    or @retcode <> 0
  22724.                 begin
  22725.                 RAISERROR(20054 , 16, -1)
  22726.                 return (1)
  22727.             end
  22728.         end
  22729.     else        
  22730.         begin
  22731.             /* Insert the schema change */
  22732.             select @schemaversion = schemaversion from sysmergeschemachange
  22733.             if (@schemaversion is NULL)
  22734.                 set @schemaversion = 1
  22735.             else
  22736.                 select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
  22737.  
  22738.             /* update the schema version and schemaguid in MSmerge_replinfo */        
  22739.             declare @srvid         int
  22740.             declare @repid         uniqueidentifier
  22741.             declare @MSmerge_replinfoschemaversion     int
  22742.             declare @MSmerge_replinfoschemaguid     uniqueidentifier
  22743.  
  22744.             select @srvid = 0
  22745.             select  @repid = repid from MSmerge_replinfo 
  22746.                 where repid in (select subid from sysmergesubscriptions
  22747.                     where srvid = @srvid and db_name = DB_NAME() and pubid = @pubid)
  22748.  
  22749.             select @MSmerge_replinfoschemaversion = schemaversion, @MSmerge_replinfoschemaguid = schemaguid
  22750.                     from dbo.MSmerge_replinfo where repid = @repid 
  22751.  
  22752.             /* 
  22753.             ** If the schema version matches the MSmerge_replinfo.schemaversion and the schema_type = 52 (snapshot trailer), 
  22754.             ** then reuse the MSmerge_replinfo.schema_guid. Otherwise generate a new guid.
  22755.             */
  22756.             if @MSmerge_replinfoschemaversion is NOT NULL and @schemaversion = @MSmerge_replinfoschemaversion and @schematype = 52
  22757.                 begin
  22758.                     set @schemaguid = @MSmerge_replinfoschemaguid
  22759.                 end
  22760.             else
  22761.                 begin
  22762.                     set @schemaguid = newid()
  22763.                 end
  22764.                 
  22765.             exec @retcode = dbo.sp_MSinsertschemachange @pubid, @artid, @schemaversion, 
  22766.                 @schemaguid, @schematype, @schematext
  22767.             if @@error <> 0    or @retcode <> 0
  22768.                 begin
  22769.                     RAISERROR(20054 , 16, -1)
  22770.                     return (1)
  22771.                 end
  22772.         end
  22773.     if (@schematype = 7)
  22774.         begin
  22775.             update sysmergesubscriptions set last_validated=getdate() where pubid=@pubid and subid=@pubid
  22776.             IF @@ERROR <> 0
  22777.             begin
  22778.                 RAISERROR(20054 , 16, -1)
  22779.                 RETURN (1)
  22780.             end
  22781.         end        
  22782.     return (0)
  22783. go
  22784. exec dbo.sp_MS_marksystemobject sp_MSadd_mergereplcommand 
  22785. go
  22786. grant exec on dbo.sp_MSadd_mergereplcommand to public
  22787. go
  22788. raiserror('Creating procedure sp_MSsetreplicainfo', 0,1)
  22789. GO
  22790.  
  22791. CREATE PROCEDURE sp_MSsetreplicainfo
  22792.     (@publisher            sysname,
  22793.      @publisher_db        sysname,
  22794.      @publication         sysname,
  22795.      @datasource_type    int = 0,             /* 0 = SQL Server, 1 = DSN, 2 = Jet */
  22796.      @server_name        sysname    = NULL, /* Server Name */
  22797.      @db_name            sysname = NULL, /* Database Name */
  22798.      @datasource_path    nvarchar(255) = NULL,/* Datasource path - JET MDB file path etc */
  22799.      @nickname     int = NULL,
  22800.      @schemaversion int = NULL,
  22801.      @subid    uniqueidentifier = NULL)
  22802. as
  22803.     declare     @pubid         uniqueidentifier
  22804.     declare     @repid         uniqueidentifier
  22805.     declare        @srvid        int
  22806.     declare        @retcode    int
  22807.  
  22808.     /*
  22809.     ** NOTE -- WORKAROUND ODBC PROBLEM
  22810.     */
  22811.     select @publisher_db = RTRIM(@publisher_db)
  22812.     select @db_name = RTRIM(@db_name)
  22813.  
  22814.     -- check that publication is valid. get pubid first since needed for security check
  22815.     select @pubid = pubid from sysmergepublications 
  22816.         where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
  22817.     if (@pubid is null)
  22818.     begin
  22819.         RAISERROR (20026, 11, -1, @publication)
  22820.         return (1)
  22821.     end
  22822.  
  22823.     /*
  22824.     ** Publisher and Subscriber permission check - different checks
  22825.     ** However ispaluser checks for dbo as well. so just calling it should do.
  22826.     */
  22827.     if ({ fn ISPALUSER(@pubid) } <> 1)
  22828.     begin    
  22829.         RAISERROR (14126, 11, -1)
  22830.         return (1)
  22831.     end
  22832.     
  22833.     /*
  22834.     ** Parameter Check:  @publication.
  22835.     ** Make sure that the publication exists.
  22836.     */
  22837.     if (@publication is null)
  22838.         begin
  22839.         RAISERROR(14043, 16, -1, '@publication')
  22840.         return (1)
  22841.         end
  22842.  
  22843.     if (@server_name is NULL)
  22844.         SET @server_name = @@SERVERNAME
  22845.  
  22846.     if (@db_name is NULL)
  22847.         set @db_name = db_name()
  22848.         
  22849.     SELECT @srvid = srvid FROM master..sysservers WHERE UPPER(srvname) = UPPER(@server_name) collate database_default
  22850.        IF @@ERROR <> 0 or @srvid IS NULL
  22851.            BEGIN
  22852.             RAISERROR(20021, 16, -1)
  22853.              RETURN (1)
  22854.         END
  22855.  
  22856.     if (@datasource_type = 0)
  22857.         begin
  22858.             /*
  22859.             ** SQL Server
  22860.             */
  22861.             SELECT @repid = subid FROM sysmergesubscriptions
  22862.                 WHERE srvid = @srvid and db_name = @db_name and pubid = @pubid
  22863.             update sysmergesubscriptions set validation_level = 0, resync_gen=-1 where subid=@repid
  22864.         END
  22865.     ELSE IF (@datasource_type = 4) or (@datasource_type = 5)
  22866.         BEGIN
  22867.             /* 
  22868.             ** Exchange or Oracle 
  22869.             */
  22870.             SELECT @repid = subid FROM sysmergesubscriptions
  22871.                 WHERE srvid = @srvid and pubid = @pubid
  22872.         END
  22873.     ELSE
  22874.         BEGIN
  22875.             /*
  22876.             ** Jet
  22877.             */
  22878.             SELECT @repid = subid FROM sysmergesubscriptions
  22879.                 WHERE datasource_path = @datasource_path and pubid = @pubid
  22880.         END
  22881.     if @repid is NULL
  22882.         begin
  22883.             RAISERROR(20021, 16, -1)
  22884.             return (1)
  22885.         end
  22886.  
  22887.     update sysmergesubscriptions set status=1 where subid=@repid and (status=5 or status=0)
  22888.  
  22889.     if @schemaversion is not null
  22890.         begin
  22891.             update MSmerge_replinfo set schemaversion = @schemaversion where repid = @repid
  22892.             if @@error <> 0        
  22893.                 begin
  22894.                     RAISERROR(20054 , 16, -1)
  22895.                     return (1)
  22896.                 end
  22897.         end
  22898.         
  22899.     if @subid is not null and @subid <> @repid
  22900.         begin
  22901.         /* Fix the repid for pull subscribers before we copy around global replica rows */
  22902.         update MSmerge_replinfo set repid = @subid where repid = @repid
  22903.         if @@error <> 0        
  22904.             begin
  22905.                 RAISERROR(20054 , 16, -1)
  22906.                 return (1)
  22907.             end
  22908.         update sysmergesubscriptions set subid = @subid where subid = @repid
  22909.         if @@error <> 0        
  22910.             begin
  22911.                 RAISERROR(20054 , 16, -1)
  22912.                 return (1)
  22913.             end
  22914.         end
  22915.         
  22916.     if @nickname IS NOT NULL        
  22917.         begin
  22918.             /* If this nickname isn't already assigned, reset it */
  22919.             if exists (select * from MSmerge_replinfo, sysmergesubscriptions
  22920.                     where replnickname = @nickname and repid = subid and (srvid <> @srvid or
  22921.                                 db_name <> @db_name))
  22922.                 return (0)
  22923.             update MSmerge_replinfo set replnickname = @nickname where repid = @repid
  22924.             if @@error <> 0        
  22925.                 begin
  22926.                     RAISERROR(20054 , 16, -1)
  22927.                     return (1)
  22928.                 end
  22929.         end            
  22930.     
  22931.     return (0)
  22932. go
  22933.  
  22934. exec dbo.sp_MS_marksystemobject sp_MSsetreplicainfo
  22935. go
  22936. grant exec on dbo.sp_MSsetreplicainfo to public
  22937. go
  22938.  
  22939. raiserror('Creating procedure sp_MSsetreplicastatus', 0,1)
  22940. GO
  22941.  
  22942. CREATE PROCEDURE sp_MSsetreplicastatus
  22943.     (@subid uniqueidentifier,
  22944.      @status_value int
  22945.      ) AS
  22946.      
  22947.     /*
  22948.     ** Check to see if current publication has permission
  22949.     */
  22950.     declare @retcode int
  22951.  
  22952.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @repid = @subid
  22953.     if @retcode<>0 or @@ERROR<>0 return (1)
  22954.     
  22955.      IF EXISTS (select subid from sysmergesubscriptions where subid=@subid)
  22956.          begin
  22957.             update sysmergesubscriptions set status = @status_value, resync_gen=-1 WHERE subid=@subid                
  22958.              if @@ERROR<>0 return (1)
  22959.             -- Now that we have changed a replica's status we might be ready to
  22960.             -- cleanup metadata or something like that.
  22961.             exec @retcode = sp_MSquiescecheck                    
  22962.              if @@ERROR<>0 or @retcode <> 0 return (1)
  22963.          end
  22964.     return (0)
  22965. go
  22966. exec dbo.sp_MS_marksystemobject sp_MSsetreplicastatus
  22967. go
  22968. grant exec on dbo.sp_MSsetreplicastatus to public
  22969. go
  22970.  
  22971.  
  22972. raiserror('Creating procedure sp_MScreateglobalreplica', 0,1)
  22973. GO
  22974.  
  22975. CREATE PROCEDURE sp_MScreateglobalreplica(
  22976.     @pubid                     uniqueidentifier = NULL,            /* Publication ID */
  22977.     @subid                     uniqueidentifier,          /* Replica ID */
  22978.     @partnerid                 uniqueidentifier,          /* Partner's Replica ID */
  22979.     @replica_server            sysname,         /* Replica server */
  22980.     @replica_db                sysname,          /* Replica database */
  22981.     @replica_priority        real,                  /* Replica priority */
  22982.     @subscriber_type        tinyint = 0,        /* Replica's subscriber type - global, hub */
  22983.     @subscription_type         int = 0,            /* Replica's subscription type - push or pull */
  22984.     @datasource_type         int = 0,
  22985.     @datasource_path         nvarchar(255) = NULL,
  22986.     @nickname                int,                /* Replica nickname */
  22987.     @status                    int,                /* Replica status */
  22988.     @sync_type                 tinyint = 2,        /* Replica sync type 1 = no sync, 2 = automatic */
  22989.     @publication            sysname = NULL,        /* Replica publication */
  22990.     @distributor            sysname = NULL        /* Replica's distributor */
  22991.     ) AS
  22992.     
  22993.     SET NOCOUNT ON
  22994.  
  22995.     /*
  22996.     ** Declarations.
  22997.     */
  22998.     DECLARE @replica_srvid        int
  22999.     DECLARE @pubnickname        int
  23000.     declare @retcode            int
  23001.     /*
  23002.     ** Check to see if in the PAL of any publication in the current database
  23003.     ** we cannot check for the current publication because the replica
  23004.     ** information passed in could be for a totally different publication
  23005.     */
  23006.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck
  23007.     if @retcode<>0 or @@ERROR<>0 return (1)
  23008.     
  23009.     /*
  23010.     ** NOTE
  23011.     */
  23012.     select @replica_db = RTRIM(@replica_db)
  23013.     /* 
  23014.     ** Initializations
  23015.     */
  23016.     SELECT @replica_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@replica_server) collate database_default
  23017.     if @replica_srvid is NULL
  23018.         begin
  23019.         EXECUTE @retcode = dbo.sp_addserver @replica_server, @duplicate_ok='duplicate_ok'
  23020.  
  23021.         IF @@error <> 0 OR @retcode <> 0
  23022.             BEGIN
  23023.                 RAISERROR (14042, 16, -1)
  23024.                 RETURN (1)
  23025.             END
  23026.         end                
  23027.     SELECT @replica_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@replica_server) collate database_default
  23028.  
  23029.     BEGIN TRAN MScreateglobalreplica    
  23030.         /*
  23031.         ** Populate the local copy of sysmergesubscriptions
  23032.         */
  23033.         if exists (select * from sysmergesubscriptions where subid = @subid)
  23034.             begin
  23035.                 update sysmergesubscriptions 
  23036.                     SET    subid                 = @subid,
  23037.                         datasource_type     = @datasource_type,
  23038.                         datasource_path     = @datasource_path,
  23039.                         srvid                 = @replica_srvid,
  23040.                         db_name             = @replica_db,
  23041.                         pubid                 = @pubid,
  23042.                         status                 = @status,
  23043.                         subscriber_type     = @subscriber_type,
  23044.                         subscription_type     = @subscription_type,
  23045.                         priority             = @replica_priority,
  23046.                         sync_type            = @sync_type,
  23047.                         login_name            = suser_sname(suser_sid()),
  23048.                         subscriber_server    = @replica_server,
  23049.                         publication            = @publication,
  23050.                         distributor            = @distributor
  23051.                 where subid = @subid and pubid = @pubid                         
  23052.             IF @@ERROR <> 0
  23053.                 goto FAILURE
  23054.             end
  23055.         else
  23056.             begin
  23057.                 /* 
  23058.                 ** If attempting to tell the current replica about another replica whose pubid IS NULL
  23059.                 ** ignore the insert because current replica has more current info.
  23060.                 */
  23061.                 if exists (select * from sysmergesubscriptions where subid = @subid and @pubid IS NULL)
  23062.                     goto SUCCESS
  23063.                     
  23064.                 IF EXISTS (SELECT * FROM sysmergesubscriptions WHERE
  23065.                     srvid = @replica_srvid AND db_name = @replica_db and pubid = @pubid)
  23066.                     goto SUCCESS
  23067.                     
  23068.                 if not exists (select * from sysmergesubscriptions where subid=@subid)
  23069.                 begin
  23070.                     insert sysmergesubscriptions(subid, partnerid, datasource_type, datasource_path, 
  23071.                         srvid, db_name, pubid, status, subscriber_type, subscription_type, priority, 
  23072.                         sync_type, login_name, subscriber_server, publication, distributor)
  23073.                     values (@subid, @partnerid, @datasource_type, @datasource_path, 
  23074.                         @replica_srvid, @replica_db, @pubid, @status, @subscriber_type, @subscription_type, @replica_priority, 
  23075.                         @sync_type, suser_sname(suser_sid()), @replica_server, @publication, @distributor)
  23076.                     IF @@ERROR <> 0
  23077.                         goto FAILURE
  23078.                 end
  23079.             end
  23080.         if not exists (select * from MSmerge_replinfo where repid = @subid )
  23081.             begin
  23082.     
  23083.                 INSERT INTO  MSmerge_replinfo(repid, replnickname)    
  23084.                     values (@subid, @nickname) 
  23085.                 IF @@ERROR <> 0
  23086.                     goto FAILURE
  23087.             end
  23088. SUCCESS:            
  23089.     COMMIT TRAN            
  23090.     RETURN 0
  23091.  
  23092. FAILURE:
  23093.     /* UNDONE : This code is specific to 6.X nested transaction semantics */
  23094.     if @@TRANCOUNT = 1 
  23095.         ROLLBACK TRANSACTION MScreateglobalreplica
  23096.     else
  23097.         COMMIT TRANSACTION
  23098.     
  23099.     RAISERROR (14057, 16, -1)
  23100.     RETURN 1
  23101. go
  23102. exec dbo.sp_MS_marksystemobject sp_MScreateglobalreplica
  23103. go
  23104. grant exec on dbo.sp_MScreateglobalreplica to public
  23105. go
  23106.  
  23107. raiserror('Creating procedure sp_MSsetconflictscript', 0,1)
  23108. GO
  23109.  
  23110. /* Add the conflict script pointer to sysmergearticles - Used by snapshot */
  23111. CREATE PROCEDURE sp_MSsetconflictscript (
  23112.     @publication        sysname,
  23113.     @article            sysname,
  23114.     @conflict_script    nvarchar(255),
  23115.     @login                sysname =NULL,
  23116.     @password            nvarchar(524) =NULL
  23117.     ) AS
  23118.  
  23119.     declare @artid uniqueidentifier
  23120.     declare @pubid uniqueidentifier
  23121.     
  23122.     /*
  23123.     ** Check for publish permission.
  23124.     */
  23125.     declare @retcode int
  23126.     exec @retcode=sp_MSreplcheck_publish
  23127.     if @retcode<>0 or @@ERROR<>0 return (1)
  23128.     
  23129.     select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name()
  23130.     if @pubid IS NULL
  23131.         BEGIN
  23132.             RAISERROR (20026, 16, -1, @publication)
  23133.             RETURN (1)
  23134.         END
  23135.     
  23136.     select @artid = artid FROM sysmergearticles WHERE name = @article    AND pubid = @pubid
  23137.     if @artid IS NULL
  23138.         BEGIN
  23139.             RAISERROR (20027, 16, -1, @article)
  23140.             RETURN (1)
  23141.         END
  23142.  
  23143.     update sysmergearticles set conflict_script = @conflict_script where artid = @artid and pubid=@pubid
  23144.     if @@ERROR <> 0
  23145.         return (1)
  23146.     return (0)
  23147. go
  23148. exec dbo.sp_MS_marksystemobject sp_MSsetconflictscript 
  23149. go
  23150. grant exec on dbo.sp_MSsetconflictscript to public
  23151. go
  23152.  
  23153. raiserror('Creating procedure sp_MSsetconflicttable', 0,1)
  23154. GO
  23155.  
  23156. /* Add the conflict table pointer to sysmergearticles - Used by reconciler */
  23157. CREATE PROCEDURE sp_MSsetconflicttable (
  23158.     @article            sysname,
  23159.     @conflict_table        nvarchar(255),
  23160.     @publisher            sysname = NULL,
  23161.     @publisher_db        sysname = NULL, 
  23162.     @publication        sysname = NULL
  23163.     ) AS
  23164.  
  23165.     declare @artid uniqueidentifier
  23166.     declare @pubid uniqueidentifier
  23167.     declare @quoted_conflict_table nvarchar(270)
  23168.     declare @basetableid    int
  23169.     
  23170.     --special case'd this out for backward compatibility with 7.0 subscribers.
  23171.     if @publisher is NULL and @publisher_db is NULL and @publication is NULL
  23172.         return (0)
  23173.  
  23174.     select @pubid=pubid    from sysmergepublications 
  23175.         where name=@publication and LOWER(publisher)=LOWER(@publisher) and publisher_db=@publisher_db
  23176.     if @pubid IS NULL
  23177.         BEGIN
  23178.             RAISERROR (20026, 16, -1, @publication)
  23179.             RETURN (1)
  23180.         END
  23181.         
  23182.     select @artid = artid, @basetableid=objid FROM sysmergearticles WHERE name = @article and pubid=@pubid    
  23183.     if @artid IS NULL
  23184.         BEGIN
  23185.             RAISERROR (20027, 16, -1, @article)
  23186.             RETURN (1)
  23187.         END
  23188.  
  23189.     /*
  23190.     ** Check to see if current publication has permission
  23191.     */
  23192.     declare @retcode int
  23193.  
  23194.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @artid = @artid, @pubid = @pubid
  23195.     if @retcode<>0 or @@ERROR<>0 return (1)
  23196.  
  23197.     select @quoted_conflict_table = quotename(@conflict_table)
  23198.     exec @retcode = dbo.sp_MS_marksystemobject @quoted_conflict_table
  23199.     
  23200.     update sysmergearticles set conflict_table = @conflict_table where artid = @artid and pubid=@pubid
  23201.     if @@ERROR <> 0
  23202.         return (1)
  23203.  
  23204.     declare @rgcol nvarchar(135)
  23205.     declare @indname nvarchar(131)
  23206.     declare @owner sysname
  23207.     declare @quotedname nvarchar(270)
  23208.         
  23209.     select @rgcol = QUOTENAME(name) from syscolumns where id = @basetableid and
  23210.                 ColumnProperty(id, name, 'isrowguidcol') = 1
  23211.     select @owner=user_name(uid) from sysobjects where name=@conflict_table
  23212.     select @indname = 'uc_' + @conflict_table
  23213.     if len(@indname) > 128
  23214.         begin
  23215.             select @indname = substring(@indname,1,92) + convert(nvarchar(36), newid())
  23216.         end
  23217.     set @indname = QUOTENAME(@indname)
  23218.     set @quotedname = QUOTENAME(@owner) + '.' + QUOTENAME(@conflict_table)
  23219.  
  23220.     --only create the conflict table index when needed.
  23221.     if not exists (select * from sysindexes where id = object_id(@quotedname) and keys is not null)
  23222.         begin
  23223.             exec ('Create unique clustered index ' + @indname + ' on ' + @quotedname +
  23224.                     ' (' + @rgcol + ', origin_datasource)' )
  23225.             if @@error <> 0
  23226.                 return (1)
  23227.         end
  23228.  
  23229.     /* Create the conflict insert proc only when necessary for performance reason */
  23230.     if exists (select * from sysmergearticles where artid = @artid and pubid=@pubid and OBJECT_ID(ins_conflict_proc) is null)
  23231.         BEGIN
  23232.         exec dbo.sp_MSgetconflictinsertproc @pubid=@pubid, @artid = @artid, @output = 0
  23233.         IF @@ERROR<> 0 OR @retcode <> 0
  23234.             return (1)
  23235.         END
  23236.  
  23237.     return (0)
  23238. go
  23239. exec dbo.sp_MS_marksystemobject sp_MSsetconflicttable 
  23240. go
  23241. grant exec on dbo.sp_MSsetconflicttable to public
  23242. go
  23243.  
  23244. raiserror('Creating procedure sp_MSmakeconflictinsertproc', 0,1)
  23245. GO
  23246.  
  23247. create procedure sp_MSmakeconflictinsertproc 
  23248.     (@tablename sysname, @ownername sysname, @procname sysname, @basetableid int, @pubid uniqueidentifier=NULL)
  23249. as
  23250. declare @arglist    nvarchar(4000)
  23251. declare @header        nvarchar(4000)
  23252. declare @qualname   nvarchar(270)
  23253. declare @argname    nvarchar(270)
  23254. declare @noset        bit
  23255. declare @wherepc    nvarchar(255)
  23256. declare @id         int
  23257. declare @sync_objid    int
  23258. declare @colname nvarchar(140)
  23259. declare @typename sysname
  23260. declare @colid smallint
  23261. declare @status tinyint
  23262. declare @len smallint
  23263. declare @prec smallint
  23264. declare @scale int
  23265. declare @retcode smallint
  23266. declare @sys_loop bit
  23267. declare @old_colname nvarchar(140)
  23268. declare @create_time_col nvarchar(8)
  23269. declare @p_number_for_conflict_type nvarchar(270)
  23270. declare @idstr nvarchar(12)
  23271. declare @pubidstr nvarchar(40)
  23272. declare @tablenick    int
  23273. declare @tablenickstr nvarchar(12)
  23274. declare @basetablename   nvarchar(270)
  23275. declare @qualifiedbasetable   nvarchar(270)
  23276. declare @basetableowner   nvarchar(270)
  23277.  
  23278. set nocount on
  23279.  
  23280. select @sys_loop = 0
  23281. set @create_time_col = NULL
  23282. set @id = NULL
  23283.  
  23284. /*
  23285. ** To check if specified object exists in current database
  23286. */
  23287. select @id = id, @ownername=user_name(uid) from sysobjects where name = @tablename
  23288.     if @id is NULL return (1)
  23289.  
  23290. select @idstr = convert(nvarchar(12),@id), @pubidstr = case when @pubid is null then 'NULL' else 
  23291.                 '''' + convert(nvarchar(40),@pubid) + '''' end
  23292.  
  23293. -- security check
  23294. exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @pubid=@pubid, @objid=@id
  23295. if @@error <> 0 or @retcode <> 0
  23296.     return 1
  23297.  
  23298. set @qualname = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename)
  23299.  
  23300. set @basetablename= object_name(@basetableid)
  23301. select @basetableowner= user_name(uid) from dbo.sysobjects where id=@basetableid
  23302.  
  23303. if @basetableowner is not null
  23304.     set @qualifiedbasetable= quotename(@basetableowner) + '.' + quotename(@basetablename)
  23305. else
  23306.     set @qualifiedbasetable= quotename(@basetablename)
  23307.  
  23308. execute @retcode= dbo.sp_MStablenickname @basetableowner, @basetablename, @tablenick output
  23309. if @@ERROR <>0 OR @retcode <>0 return (1)
  23310. set @tablenickstr = rtrim(convert(nchar, @tablenick))
  23311.  
  23312. -- create temp table to select the command text out of
  23313. create table #tempcmd (phase int NOT NULL, step int identity NOT NULL, 
  23314. cmdtext nvarchar(4000) collate database_default null)
  23315.  
  23316. create table #coltab (colname nvarchar(140), paramname nvarchar(10))
  23317.  
  23318. -- now create the procedure
  23319. select @procname = QUOTENAME(@procname)
  23320.  
  23321. select @header = 'Create procedure dbo.' + @procname + ' ( ' 
  23322. insert into #tempcmd (phase, cmdtext) values (0,  @header)
  23323.  
  23324. select @sync_objid = sync_objid from sysmergearticles where objid = @basetableid and (pubid = @pubid or @pubid is NULL)
  23325.  
  23326. select @colid = min(colid) from syscolumns where id = @id and iscomputed <>1 and 
  23327.     type_name(xtype) <> 'timestamp' and ((name not in (select name from syscolumns where id=@basetableid) 
  23328.         and @sys_loop =1) OR
  23329.      (name in (select name from syscolumns where id=@basetableid) and @sys_loop =0))
  23330. select @colname = c.name, @status = c.status, @typename = t.name, @len = c.length,
  23331.     @prec = c.prec, @scale = c.scale
  23332.     from syscolumns c, systypes t
  23333.     where c.id = @id and c.colid = @colid and c.xusertype = t.xusertype 
  23334.  
  23335. /*
  23336. ** Get the column list from the conflict_table schema and filter it with 
  23337. table view for vertical partitioning
  23338. */
  23339. Reverse_Order:
  23340. while (@colname is not null) 
  23341. begin
  23342.     set @noset = 0
  23343.     if exists (select * from syscolumns where name=@colname and id=@basetableid)
  23344.         and not exists (select * from syscolumns where name=@colname and id=@sync_objid)
  23345.         goto NEXT_COL         
  23346.     if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
  23347.         select @len = @len/2
  23348.     exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale
  23349.     if @@ERROR<>0 or @retcode<>0 return (1)
  23350.     select @argname = '@p' + rtrim(convert(nchar, @colid))
  23351.     
  23352.     insert into #coltab (colname, paramname) values (quotename(@colname), @argname)
  23353.  
  23354.     if LOWER(@colname collate SQL_Latin1_General_CP1_CS_AS)='conflict_type'
  23355.         select @p_number_for_conflict_type=@argname
  23356.         
  23357.     -- based on colid, add text to appropriate pieces
  23358.     if (COLUMNPROPERTY( @basetableid, @colname, 'IsRowGuidCol') = 1)  
  23359.         begin
  23360.             select @noset =1
  23361.             set @wherepc = ' where rowguidcol = ' + @argname
  23362.         end
  23363.     else if (@colname = 'origin_datasource')
  23364.         begin
  23365.             select @wherepc =@wherepc +  ' and origin_datasource = ' + @argname
  23366.             set @noset =1
  23367.         end
  23368.     set @old_colname = @colname
  23369.     set @colname = QUOTENAME(@colname)
  23370.     if @arglist is null
  23371.         begin
  23372.         set @arglist = @argname + ' ' + @typename
  23373.         --give default value of NULL to new merge columns for backward compatibility concern
  23374.         insert into #tempcmd (phase, cmdtext) values (3, @colname)
  23375.         select @header = ') values ('
  23376.         insert into #tempcmd (phase, cmdtext) values (4, @header)
  23377.  
  23378.         insert into #tempcmd (phase, cmdtext) values (4, @argname)
  23379.         if @noset=0
  23380.             insert into #tempcmd (phase, cmdtext) values (1, @colname + ' = ' + @argname)
  23381.         end
  23382.     else 
  23383.         begin
  23384.         if len(@arglist)>3700
  23385.             begin
  23386.                 insert into #tempcmd (phase, cmdtext) values (0,  @arglist)            
  23387.                 select @arglist = ' '
  23388.             end
  23389.         set @arglist = @arglist + ', ' + @argname + ' ' + @typename
  23390.         if @sys_loop = 1 and @old_colname not in ('origin_datasource','conflict_type','reason_code','reason_text', 'pubid') 
  23391.             begin
  23392.                 select @arglist=@arglist + ' = NULL'        
  23393.                 if @old_colname='MSrepl_create_time'
  23394.                     select @create_time_col=@argname
  23395.             end
  23396.  
  23397.         insert into #tempcmd (phase, cmdtext) values (3, ',' + @colname)
  23398.  
  23399.         insert into #tempcmd (phase, cmdtext) values (4, ',' + @argname)
  23400.  
  23401.         if @noset =0
  23402.             begin
  23403.                 if exists (select * from #tempcmd where phase=1)
  23404.                     insert into #tempcmd (phase, cmdtext) values (1, ',' + @colname + ' = ' + @argname)
  23405.                 else
  23406.                     insert into #tempcmd (phase, cmdtext) values (1, @colname + ' = ' + @argname)
  23407.             end
  23408.         end
  23409. NEXT_COL:
  23410.     select @colid = min(colid) from syscolumns where id = @id and colid>@colid and iscomputed <>1 and 
  23411.         type_name(xtype) <> 'timestamp' and 
  23412.         ((name not in (select name from syscolumns where id=@basetableid) and @sys_loop =1) OR
  23413.              (name in (select name from syscolumns where id=@basetableid) and @sys_loop =0))
  23414.     set @colname = NULL
  23415.     select @colname = c.name, @status = c.status, @typename = t.name, @len = c.length,
  23416.         @prec = c.prec, @scale = c.scale
  23417.         from syscolumns c, systypes t
  23418.         where c.id = @id and c.colid = @colid and c.xusertype = t.xusertype
  23419. end
  23420.  
  23421. if @sys_loop = 0
  23422. begin
  23423.     select @sys_loop = 1
  23424.     select @colid = min(colid) from syscolumns where id = @id  and iscomputed <>1 
  23425.         and type_name(xtype) <> 'timestamp' and 
  23426.         ((name not in (select name from syscolumns where id=@basetableid) and @sys_loop =1) OR
  23427.          (name in (select name from syscolumns where id=@basetableid) and @sys_loop =0))
  23428.     select @colname = c.name, @status = c.status, @typename = t.name, @len = c.length,
  23429.         @prec = c.prec, @scale = c.scale
  23430.         from syscolumns c, systypes t
  23431.             where c.id = @id and c.colid = @colid and c.xusertype = t.xusertype 
  23432.     goto Reverse_Order
  23433. end
  23434.  
  23435. insert into #tempcmd (phase, cmdtext) values (0,  @arglist)            
  23436.  
  23437. select @header =  ') as
  23438. declare @retcode int
  23439. -- security check
  23440. exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @objid = ' + @idstr + ', @pubid = ' + @pubidstr + '
  23441. if @@error <> 0 or @retcode <> 0
  23442.     return 1 '
  23443. insert into #tempcmd (phase, cmdtext) values (0,  @header)
  23444.  
  23445. select @header = ' '
  23446. -- for ease of expansion here in case we add new merge columns in conflict tables.
  23447. if @create_time_col is not NULL
  23448.     select @header = @header + ' 
  23449.         select ' + @create_time_col + ' = getdate() '
  23450.  
  23451. select @header = @header + ' if exists (select * from ' + @qualname + ' ' + @wherepc + ')
  23452.     begin
  23453.     update ' + @qualname + ' set ' 
  23454. insert into #tempcmd (phase, cmdtext) values (0,  @header)
  23455.  
  23456. --see comment in sp_MSinsertdeleteconflict for this <5 or >4 checking.
  23457.  
  23458. select @header = @wherepc + ' and (conflict_type<5 or ' + @p_number_for_conflict_type + ' >4) 
  23459.     end
  23460.     else
  23461.     insert into ' + @qualname + ' ('
  23462. insert into #tempcmd (phase, cmdtext) values (2,  @header)
  23463.  
  23464. insert into #tempcmd (phase, cmdtext) values (4, ')')
  23465.  
  23466. exec dbo.sp_MScreatedupkeyupdatequery
  23467.             @tablename= @qualifiedbasetable,
  23468.             @tablenickstr= @tablenickstr,
  23469.             @phase= 4,
  23470.             @isconflictproc= 1
  23471.  
  23472. -- Now we select out the command text pieces in proper order so that our caller,
  23473. -- xp_execresultset will execute the command that creates the stored procedure.
  23474.  
  23475. select cmdtext from #tempcmd order by phase, step
  23476. drop table #tempcmd
  23477. drop table #coltab
  23478. go
  23479. exec dbo.sp_MS_marksystemobject sp_MSmakeconflictinsertproc 
  23480. go
  23481. grant exec on dbo.sp_MSmakeconflictinsertproc to public
  23482. go
  23483.  
  23484. dump tran master with no_log
  23485. go
  23486.  
  23487.  
  23488. raiserror('Creating procedure sp_MSmaketempinsertproc', 0,1)
  23489. GO
  23490.  
  23491. -- Create temp sp, no security check needed
  23492. create procedure sp_MSmaketempinsertproc 
  23493.     (@tablename sysname, @procname sysname)
  23494. as
  23495. declare @arglist    nvarchar(4000)
  23496. declare @collist    nvarchar(4000)
  23497. declare @vallist     nvarchar(4000)
  23498. declare @argname    sysname
  23499. declare @setpc        nvarchar(4000)
  23500. declare @wherepc    nvarchar(255)
  23501.  
  23502. declare @qualname nvarchar(270)
  23503. declare @id int
  23504.  
  23505. set @qualname = 'tempdb..' + @tablename
  23506. select @id = id from tempdb..sysobjects where name = @tablename
  23507.  
  23508. declare @colname sysname
  23509. declare @typename sysname
  23510. declare @colid smallint
  23511. declare @status tinyint
  23512. declare @len smallint
  23513. declare @prec int
  23514. declare @scale int
  23515. declare @retcode smallint
  23516.  
  23517.     
  23518. set @wherepc = ' where rowguid = @p2 '
  23519. select @colid = 1
  23520. select @colname = c.name, @status = c.status, @typename = t.name, @len = c.length,
  23521.     @prec = COLUMNPROPERTY(c.id, c.name, 'precision'), @scale = c.scale
  23522.     from tempdb..syscolumns c, systypes t
  23523.     where c.id = @id and c.colid = @colid and c.xusertype = t.xusertype and c.iscomputed<>1 and type_name(c.xtype) <> 'timestamp' 
  23524. while (@colname is not null)
  23525.     begin
  23526.     if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
  23527.         select @len = @len/2
  23528.     exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale
  23529.     if @@error<>0 or @retcode<>0 return (1)
  23530.  
  23531.     set @argname = '@p' + rtrim(convert(nchar, @colid))
  23532.             
  23533.     if (@colid = 1)
  23534.         begin
  23535.         set @arglist = @argname + ' ' + @typename
  23536.         set @collist = @colname
  23537.         set @vallist = @argname
  23538.         set @setpc = @colname + ' = ' + @argname
  23539.         end
  23540.     else
  23541.         begin
  23542.         set @arglist = @arglist + ', ' + @argname + ' ' + @typename
  23543.         set @collist = @collist + ', ' + @colname
  23544.         set @vallist = @vallist + ', ' + @argname
  23545.         set @setpc = @setpc + ', ' + @colname + ' = ' + @argname
  23546.         end
  23547.     set @colid = @colid + 1
  23548.     set @colname = NULL
  23549.     select @colname = c.name, @status = c.status, @typename = t.name, @len = c.length,
  23550.         @prec = COLUMNPROPERTY(c.id, c.name, 'precision'), @scale = c.scale
  23551.         from tempdb..syscolumns c, systypes t
  23552.         where c.id = @id and c.colid = @colid and c.xusertype = t.xusertype 
  23553.             and c.iscomputed<>1 and type_name(c.xtype)<>'timestamp' 
  23554.     end
  23555. declare @qual_tablename nvarchar(140)
  23556. declare @qual_procname nvarchar(140)
  23557. select @qual_procname = QUOTENAME(@procname)
  23558. select @qual_tablename = QUOTENAME(@tablename)
  23559. -- now create the procedure
  23560. execute ('Create procedure dbo.' + @qual_procname + ' ( ' + @arglist + ') as
  23561.     update ' + @qual_tablename + ' set ' + @setpc + @wherepc + '
  23562.     if (@@rowcount = 0)
  23563.     insert into ' + @qual_tablename + ' (' + @collist + ') values (' + @vallist + ')')
  23564. if @@ERROR<>0
  23565.     begin
  23566.         return(1)
  23567.     end
  23568. go
  23569. exec dbo.sp_MS_marksystemobject sp_MSmaketempinsertproc 
  23570. go
  23571.  
  23572. raiserror('Creating procedure sp_MSgetconflictinsertproc', 0,1)
  23573. GO
  23574.  
  23575. /* Add the conflict table pointer to sysmergearticles - Used by reconciler */
  23576. CREATE PROCEDURE sp_MSgetconflictinsertproc (
  23577.     @artid                 uniqueidentifier,
  23578.     @pubid                uniqueidentifier = NULl,
  23579.     @output    int = 1
  23580.     ) AS
  23581.     declare @conflict_table sysname
  23582.     declare @conflict_proc    sysname
  23583.     declare @owner             sysname
  23584.     declare @object            sysname
  23585.     declare @retcode         int
  23586.     declare @quoted_conflict_table    nvarchar(270)
  23587.     declare    @basetableid    int
  23588.     declare @sync_objid            int
  23589.     declare @command              nvarchar(1000)
  23590.     declare @pubidstr             nvarchar(40)
  23591.     declare @dbname                sysname
  23592.     declare @conflict_table_id     int
  23593.     -- PARSENAME VARS
  23594.     declare @UnqualName     nvarchar(270)  --rightmost name node
  23595.     declare @QualName1      nvarchar(270)  
  23596.     declare @QualName2      nvarchar(270)  
  23597.     -- END PARSENAME VARS
  23598.  
  23599.     declare @guidstr varchar(40)
  23600.     exec @retcode=sp_MSguidtostr @artid, @guidstr out
  23601.     if @retcode<>0 or @@ERROR<>0 return (1)
  23602.     
  23603.     /*
  23604.     ** Check to see if current publication has permission
  23605.     */
  23606.     if @pubid is NULL
  23607.     begin
  23608.         -- this is a slow security check
  23609.         exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @artid = @artid
  23610.         if @retcode<>0 or @@ERROR<>0 return (1)
  23611.     end
  23612.     else
  23613.     begin
  23614.         if ({ fn ISPALUSER(@pubid) } <> 1)
  23615.         begin    
  23616.             RAISERROR (14126, 11, -1)
  23617.             return (1)
  23618.         end
  23619.     end
  23620.  
  23621.     /*
  23622.     ** @pubid is NULL - means that subscriber is 7.0, in which case there is no
  23623.     ** vertical partitioning allowed. getting the proc from any publication is fine.
  23624.     */
  23625.     select @conflict_table = conflict_table, @conflict_proc = ins_conflict_proc, 
  23626.             @basetableid = objid, @sync_objid = sync_objid 
  23627.     from sysmergearticles where artid = @artid and (pubid=@pubid OR @pubid is NULL)
  23628.  
  23629.     if @@ERROR <> 0
  23630.         return (1)
  23631.  
  23632.     select @conflict_table_id = object_id(@conflict_table)
  23633.     if @conflict_table_id is NULL  --check if it is caused by different owner name
  23634.         select @conflict_table_id=id from sysobjects where name=@conflict_table
  23635.  
  23636.     select @quoted_conflict_table = QUOTENAME(@conflict_table)
  23637.     if ( @conflict_table_id is not null)
  23638.     begin            
  23639.         select @UnqualName = PARSENAME(@conflict_table, 1)
  23640.         select @QualName1 = PARSENAME(@conflict_table, 2)
  23641.         if @UnqualName IS NULL
  23642.              return 1
  23643.         
  23644.         -- fixup for variable length differences.  remove when vars expanded
  23645.         -- to new SQL SERVER 7.0 lengths
  23646.  
  23647.         select @owner=user_name(uid) from sysobjects where id= @conflict_table_id
  23648.         if @owner is NULL
  23649.         begin
  23650.             select @owner =  @QualName1
  23651.         end
  23652.         select @object = @UnqualName
  23653.     end
  23654.     
  23655.     -- Create an index on the conflict table if it doesn't have one
  23656.     if ( @conflict_table_id is not null) and
  23657.         not exists (select * from sysindexes where id = @conflict_table_id and keys is not null)
  23658.         begin
  23659.         declare @rgcol nvarchar(135)
  23660.         declare @indname nvarchar(270)
  23661.         declare @quotedname nvarchar(270)
  23662.         
  23663.         select @rgcol = QUOTENAME(name) from syscolumns where id = @basetableid and
  23664.                 ColumnProperty(id, name, 'isrowguidcol') = 1
  23665.         select @indname = 'uc_' + @conflict_table
  23666.         if len(@indname) > 128
  23667.         begin
  23668.             select @indname = substring(@indname,1,92) + convert(nvarchar(36), newid())
  23669.         end
  23670.         set @indname = QUOTENAME(@indname)
  23671.         set @quotedname = QUOTENAME(@owner) + '.' + QUOTENAME(@conflict_table)
  23672.         exec ('Create unique clustered index ' + @indname + ' on ' + @quotedname +
  23673.                 ' (' + @rgcol + ', origin_datasource)' )
  23674.         if @@error <> 0
  23675.             return (1)
  23676.         end
  23677.     if ((OBJECT_ID(@conflict_proc) is null) and (@conflict_table_id is not null))
  23678.         begin
  23679.         -- first set up the procedure name variable
  23680.  
  23681.         exec @retcode = dbo.sp_MSguidtostr @artid, @guidstr out
  23682.         if @@ERROR <>0 OR @retcode <>0 return (1)
  23683.  
  23684.         exec @retcode = dbo.sp_MSguidtostr @pubid, @pubidstr out
  23685.         if @@ERROR <>0 OR @retcode <>0 return (1)
  23686.  
  23687.         if @pubid is not NULL
  23688.             select @conflict_proc = 'sp_cft_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16)
  23689.         else
  23690.             select @conflict_proc = 'sp_cft_' + substring(@guidstr, 1, 32) 
  23691.  
  23692.         exec @retcode=sp_MSuniqueobjectname @conflict_proc , @conflict_proc output
  23693.         if @@ERROR <> 0 OR @retcode <> 0 
  23694.             return(1)
  23695.         set @dbname = db_name()
  23696.         if @owner is NULL
  23697.             set @command = 'sp_MSmakeconflictinsertproc ' + QUOTENAME(@conflict_table) + ' , NULL , ' + @conflict_proc  + ' , ' + convert(nvarchar,@basetableid)
  23698.         else
  23699.             set @command = 'sp_MSmakeconflictinsertproc ' + QUOTENAME(@conflict_table) + ' , ' + QUOTENAME(@owner) + ' , ' + @conflict_proc  + ' , ' + convert(nvarchar,@basetableid) 
  23700.  
  23701.         if @pubid is not NULL
  23702.             set @command = @command    + ', [' + convert(nchar(36), @pubid) + ']'
  23703.         exec @retcode = master..xp_execresultset @command, @dbname
  23704.         if @@ERROR<>0 OR @retcode<>0 
  23705.         begin
  23706.             return (1)
  23707.         end
  23708.         exec @retcode = dbo.sp_MS_marksystemobject  @conflict_proc 
  23709.         if @@ERROR<>0 or @retcode<>0  return (1)
  23710.         exec ('grant exec on ' + @conflict_proc + ' to public')
  23711.         if @@ERROR<>0 return (1)
  23712.         update sysmergearticles set ins_conflict_proc = @conflict_proc where artid = @artid and pubid=@pubid
  23713.     end
  23714.  
  23715.     if @output = 1
  23716.         select @conflict_table, @conflict_proc
  23717.     if @@ERROR <> 0
  23718.         return (1)
  23719.     return (0)
  23720.     
  23721. go
  23722. exec dbo.sp_MS_marksystemobject sp_MSgetconflictinsertproc 
  23723. go
  23724. grant exec on dbo.sp_MSgetconflictinsertproc to public
  23725. go
  23726.  
  23727. raiserror('Creating procedure sp_MSinsertdeleteconflict', 0,1)
  23728. GO
  23729.  
  23730. create PROCEDURE sp_MSinsertdeleteconflict(     
  23731.     @tablenick             int,
  23732.     @rowguid             uniqueidentifier,
  23733.     @conflict_type        int,
  23734.     @reason_code        int,
  23735.     @reason_text        nvarchar(720),
  23736.     @origin_datasource    nvarchar(255),
  23737.     @pubid                uniqueidentifier,
  23738.     @lineage             varbinary(255) = NULL,
  23739.     @conflicts_logged    INT = NULL OUTPUT)
  23740. as
  23741.     
  23742.     declare @retcode int
  23743.     /*
  23744.     ** Check to see if current publication has permission
  23745.     */
  23746.     if ({ fn ISPALUSER(@pubid) } <> 1)
  23747.     begin    
  23748.         RAISERROR (14126, 11, -1)
  23749.         return (1)
  23750.     end
  23751.  
  23752.     /* Parameter validation */
  23753.     if (@tablenick is null)
  23754.         begin
  23755.         RAISERROR(14043, 16, -1, '@tablenick')
  23756.         return (1)
  23757.         end
  23758.     if (@rowguid is null)
  23759.         begin
  23760.         RAISERROR(14043, 16, -1, '@rowguid')
  23761.         return (1)
  23762.         end
  23763.  
  23764.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  23765.         begin
  23766.         RAISERROR(20054 , 16, -1)
  23767.         return (1)
  23768.         end
  23769.     /* Don't insert a duplicate row */
  23770.     if (not exists (select * from MSmerge_delete_conflicts where tablenick = @tablenick and
  23771.         rowguid = @rowguid and origin_datasource = @origin_datasource))
  23772.         begin
  23773.             insert into MSmerge_delete_conflicts
  23774.                 (tablenick, rowguid, conflict_type, reason_code, reason_text, origin_datasource, pubid) values
  23775.                 (@tablenick, @rowguid, @conflict_type, @reason_code, @reason_text, @origin_datasource, @pubid)
  23776.             select @conflicts_logged = @@ROWCOUNT
  23777.             if @@ERROR <> 0 return (1)
  23778.         end
  23779.         /* Update the existing row - but do not use a generic message to update an error */
  23780.     else if (exists (select * from MSmerge_delete_conflicts where tablenick = @tablenick and
  23781.                 rowguid = @rowguid and origin_datasource = @origin_datasource and 
  23782.                 (conflict_type<5 or @conflict_type>4)))
  23783.         begin                
  23784.             update MSmerge_delete_conflicts set conflict_type = @conflict_type, reason_code = @reason_code,
  23785.                 reason_text = @reason_text where tablenick = @tablenick and
  23786.                 rowguid = @rowguid and origin_datasource = @origin_datasource
  23787.             select @conflicts_logged = @@ROWCOUNT
  23788.             if @@ERROR <> 0 return (1)
  23789.         end            
  23790.     
  23791.     /* If this is an error, add to MSmerge_errorlineage table */
  23792.     if @conflict_type in (7, 8) and @lineage is not null
  23793.         exec @retcode = sp_MSinserterrorlineage @tablenick, @rowguid, @lineage
  23794.     if @retcode<>0 or @@ERROR<>0 return (1)
  23795.     
  23796.     return (0)
  23797. go
  23798. exec dbo.sp_MS_marksystemobject sp_MSinsertdeleteconflict
  23799. go
  23800. grant exec on dbo.sp_MSinsertdeleteconflict to public
  23801. go
  23802.  
  23803. raiserror('Creating procedure sp_MScheckmetadatamatch', 0,1)
  23804. GO
  23805.  
  23806. create procedure sp_MScheckmetadatamatch
  23807.     (@metatype tinyint, 
  23808.      @rowguid uniqueidentifier,
  23809.      @tablenick int,
  23810.      @lineage varbinary(255),
  23811.      @match int output)
  23812. as
  23813.     if (@metatype = 3)
  23814.     begin
  23815.         if not exists (select * from dbo.MSmerge_contents where tablenick = @tablenick and rowguid = @rowguid)
  23816.             select @match = 1
  23817.         else
  23818.             select @match = count(*) from dbo.MSmerge_contents (updlock) where
  23819.                 tablenick = @tablenick and rowguid = @rowguid and lineage = @lineage
  23820.     end
  23821.     else
  23822.         select @match = count(*) from dbo.MSmerge_contents (updlock) where
  23823.                 tablenick = @tablenick and rowguid = @rowguid and lineage = @lineage
  23824.     return (0)
  23825. go
  23826. exec dbo.sp_MS_marksystemobject sp_MScheckmetadatamatch
  23827. go
  23828. grant exec on dbo.sp_MScheckmetadatamatch to public
  23829.  
  23830. raiserror('Creating procedure sp_MSdelrow', 0,1)
  23831. GO
  23832.  
  23833. create PROCEDURE sp_MSdelrow 
  23834.     (@rowguid         uniqueidentifier,
  23835.     @tablenick     int,
  23836.     @metadata_type tinyint, /* 0 - Missing, 1 - Tombstone, 2 - Contents, 3 - ContentsDeferred, 6 - system delete */
  23837.     @lineage_old varbinary(255),
  23838.     @generation int,
  23839.     @lineage_new varbinary(255),
  23840.     @pubid uniqueidentifier = NULL,
  23841.     @check_permission int = 0)
  23842.  
  23843. as
  23844.     set nocount on
  23845.     declare @match             int
  23846.     declare @new_metatype    tinyint
  23847.     declare @retcode         smallint
  23848.     declare @errcode        int
  23849.     declare @reason         nvarchar(255)
  23850.     declare @procname         sysname
  23851.     declare @objid            int
  23852.     declare @permissions    int
  23853.     
  23854.     /*
  23855.     ** Check to see if current publication has permission
  23856.     */
  23857.     if @pubid is NULL
  23858.     begin
  23859.         exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick = @tablenick
  23860.         if @retcode<>0 or @@ERROR<>0 return (1)
  23861.     end
  23862.     else
  23863.     begin
  23864.         if ({ fn ISPALUSER(@pubid) } <> 1)
  23865.         begin    
  23866.             RAISERROR (14126, 11, -1)
  23867.             return (1)
  23868.         end
  23869.     end
  23870.             
  23871.     /* Parameter validation */
  23872.     if (@rowguid is null)
  23873.     begin
  23874.         RAISERROR(14043, 16, -1, '@rowguid')
  23875.         return (0)
  23876.     end
  23877.     if (@tablenick is null)
  23878.     begin
  23879.         RAISERROR(14043, 16, -1, '@tablenick')
  23880.         return (0)
  23881.     end
  23882.     if (@lineage_new is null)
  23883.     begin
  23884.         RAISERROR(14043, 16, -1, '@lineage_new')
  23885.         return (0)
  23886.     end
  23887.  
  23888.     if @check_permission =1
  23889.     begin
  23890.         select @objid=objid, @permissions= check_permissions from sysmergearticles 
  23891.             where nickname=@tablenick and (pubid is NULL or pubid=@pubid)
  23892.         if @objid is NULL
  23893.             return (0)
  23894.  
  23895.         exec @retcode = dbo.sp_MSreplcheck_permission @objid = @objid, @type = 3, @permissions = @permissions
  23896.         if @retcode<>0 or @@ERROR<>0 return (4)
  23897.     end
  23898.  
  23899.     -- Are we just changing the type of a tombstone?
  23900.     -- This routine is only called for Upload; won't be type 5 (remove from partial) unless
  23901.     -- subscriber has a user delete and found an existing metadata type of 5 here.
  23902.     -- In that case, set delete type to 1 and update generation, reason text too.
  23903.     if (@metadata_type = 5)
  23904.     begin
  23905.         if exists (select * from dbo.MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)
  23906.         begin
  23907.             set @reason = formatmessage (20562) -- User delete
  23908.             update dbo.MSmerge_tombstone set type = 1, reason = @reason, generation = @generation, lineage = @lineage_new where
  23909.                 rowguid = @rowguid and tablenick = @tablenick
  23910.             return 1
  23911.         end
  23912.     end
  23913.     -- Are we just changing the type of a tombstone?
  23914.     else if (@metadata_type = 6)
  23915.     begin
  23916.         if exists (select * from dbo.MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)
  23917.         begin
  23918.             set @reason = formatmessage (20564) -- System deleted
  23919.             update dbo.MSmerge_tombstone set type = @metadata_type, reason = @reason,
  23920.                 generation = @generation, lineage = @lineage_new where
  23921.                 rowguid = @rowguid and tablenick = @tablenick
  23922.             return 1
  23923.         end
  23924.     end
  23925.  
  23926.     -- begin transaction and lock row that we plan to delete
  23927.     begin transaction
  23928.     save tran sp_MSdelrow
  23929.  
  23930.     select @procname = select_proc from sysmergearticles where nickname = @tablenick and pubid = @pubid
  23931.     exec @retcode = @procname @type =8, @rowguid=@rowguid
  23932.     IF @@ERROR<>0 or @retcode<>0
  23933.     begin
  23934.         set @errcode= 0
  23935.         goto Failure
  23936.     end
  23937.  
  23938.     if @metadata_type = 5
  23939.     begin
  23940.         set @match = 1
  23941.         set @new_metatype = 5
  23942.     end
  23943.     else if @metadata_type = 6
  23944.     begin
  23945.         set @match = 1
  23946.         set @new_metatype = 6
  23947.     end
  23948.     else
  23949.     begin
  23950.         exec @retcode=sp_MScheckmetadatamatch @metadata_type, @rowguid, @tablenick, @lineage_old, @match output
  23951.         IF @@ERROR<>0 or @retcode<>0
  23952.         begin
  23953.             set @errcode= 0
  23954.             goto Failure
  23955.         end
  23956.         
  23957.         set @new_metatype = 1
  23958.     end
  23959.     
  23960.     if (@match = 1)
  23961.     begin
  23962.         -- select_proc makes a delete with @type = 5, despite its name. 
  23963.         declare @rowcount int, @error int
  23964.         exec @retcode = @procname @type =5, @rowguid=@rowguid
  23965.         select @error=@@error, @rowcount=@@rowcount
  23966.         if @error<>0 or @retcode<>0
  23967.         begin
  23968.             set @errcode= 0
  23969.             goto Failure
  23970.         end
  23971.         
  23972.         if (@rowcount = 1)
  23973.         begin
  23974.             exec @retcode= dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, NULL, @new_metatype, @pubid
  23975.             IF @@ERROR<>0 or @retcode<>0
  23976.             begin
  23977.                 set @errcode= 0
  23978.                 goto Failure
  23979.             end
  23980.         end
  23981.         else
  23982.         begin
  23983.             set @errcode= 3
  23984.             goto Failure
  23985.         end
  23986.     end
  23987.     else
  23988.     begin
  23989.         set @errcode= 2
  23990.         goto Failure
  23991.     end
  23992.  
  23993.     commit tran
  23994.     return(1)-- in sp_MSdelrow, 1=okay
  23995.  
  23996. Failure:
  23997.     rollback tran sp_MSdelrow
  23998.     commit tran
  23999.     return(@errcode)
  24000. go
  24001. exec dbo.sp_MS_marksystemobject sp_MSdelrow 
  24002. go
  24003. grant exec on dbo.sp_MSdelrow to public
  24004. go
  24005.  
  24006. raiserror('Creating procedure sp_MSsetartprocs', 0,1)
  24007. GO
  24008.  
  24009. SET ANSI_NULLS ON 
  24010. SET QUOTED_IDENTIFIER ON
  24011. GO
  24012. -- Call by snapshot
  24013. create procedure sp_MSsetartprocs
  24014.     (@publication        sysname,
  24015.     @article            sysname,
  24016.     @force_flag         int = 0)
  24017. as
  24018.     declare @ownername sysname
  24019.     declare @objectname sysname
  24020.     declare @guidstr nvarchar(40)
  24021.     declare @pubidstr nvarchar(40)
  24022.     declare @conflict_proc sysname
  24023.     declare @conflict_table sysname
  24024.     declare @snapshot_ready int
  24025.     declare @ins_procname sysname
  24026.     declare @sel_procname sysname
  24027.     declare @upd_procname sysname
  24028.     declare @view_selprocname nvarchar(290)
  24029.     declare @viewname sysname
  24030.     declare @artid uniqueidentifier
  24031.     declare @pubid uniqueidentifier
  24032.     declare @objid int
  24033.     declare @rgcol nvarchar(140)
  24034.     declare @sync_objid int
  24035.     declare @retcode smallint
  24036.     declare @dbname sysname
  24037.     declare @command  nvarchar(1000)
  24038.     
  24039.     set nocount on
  24040.     /*
  24041.     ** Check to see if current publication has permission
  24042.     */
  24043.     exec @retcode=sp_MSreplcheck_publish
  24044.     if @retcode<>0 or @@ERROR<>0 return (1)
  24045.     
  24046.     -- figure out pubid and artid
  24047.     if @force_flag = 1
  24048.         begin
  24049.         -- don't qualify that must be publisher when we are forcing remake at subscribers
  24050.         select @pubid = pubid, @snapshot_ready=snapshot_ready from sysmergepublications where name = @publication and 
  24051.             pubid in (select pubid from sysmergearticles where name=@article)
  24052.         end
  24053.     else
  24054.         select @pubid = pubid, @snapshot_ready=snapshot_ready 
  24055.             from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name()
  24056.     if @pubid IS NULL
  24057.         BEGIN
  24058.             RAISERROR (20026, 16, -1, @publication)
  24059.             RETURN (1)
  24060.         END
  24061.  
  24062.     select @conflict_table=NULL
  24063.     select @artid = artid, @objid = objid, @sync_objid = sync_objid, @conflict_table=conflict_table FROM sysmergearticles WHERE name = @article    AND pubid = @pubid
  24064.     if @artid IS NULL
  24065.         BEGIN
  24066.             RAISERROR (20027, 16, -1, @article)
  24067.             RETURN (1)
  24068.         END
  24069.  
  24070.     /* Drop the article procs if they preexist */
  24071.     exec @retcode = dbo.sp_MSdroparticleprocs @pubid, @artid
  24072.     if @@ERROR<>0 OR @retcode<>0 
  24073.         begin
  24074.             return (1)
  24075.         end
  24076.     
  24077.     -- get owner name, and table name
  24078.     select @objectname = name, @ownername = user_name(uid)    from sysobjects
  24079.         where id = @objid 
  24080.  
  24081.     -- make the insert and update proc names
  24082.     exec @retcode = dbo.sp_MSguidtostr @artid, @guidstr out
  24083.     if @@ERROR <>0 OR @retcode <>0 return (1)
  24084.  
  24085.     exec @retcode = dbo.sp_MSguidtostr @pubid, @pubidstr out
  24086.     if @@ERROR <>0 OR @retcode <>0 return (1)
  24087.  
  24088.     select @ins_procname = 'sp_ins_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16)
  24089.     exec dbo.sp_MSuniqueobjectname @ins_procname, @ins_procname output
  24090.     if @@ERROR <>0 OR @retcode <>0 return (1)
  24091.     
  24092.     select @upd_procname = 'sp_upd_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16)
  24093.     exec dbo.sp_MSuniqueobjectname @upd_procname, @upd_procname output
  24094.     if @@ERROR <>0 OR @retcode <>0 return (1)
  24095.  
  24096.     select @sel_procname = 'sp_sel_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16)
  24097.     exec dbo.sp_MSuniqueobjectname @sel_procname, @sel_procname output
  24098.     if @@ERROR <>0 OR @retcode <>0 return (1)
  24099.  
  24100.     set @view_selprocname = 'sel_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16)
  24101.     exec @retcode = dbo.sp_MSuniqueobjectname @view_selprocname , @view_selprocname output
  24102.     if @retcode <> 0 or @@ERROR <> 0 return (1) 
  24103.  
  24104.     -- create the procs
  24105.     set @dbname = db_name()
  24106.  
  24107.     set @command = 'sp_MSmakeinsertproc ' + QUOTENAME(@objectname) + ' , ' + QUOTENAME(@ownername) + ' , ' + @ins_procname  + ', [' + convert(nchar(36), @pubid) + ']'
  24108.  
  24109.     exec @retcode = master..xp_execresultset @command, @dbname
  24110.  
  24111.     if @@ERROR<>0 OR @retcode<>0 
  24112.         begin
  24113.             return (1)
  24114.         end
  24115.  
  24116.  
  24117.     exec @retcode = dbo.sp_MS_marksystemobject  @ins_procname 
  24118.     if @@ERROR<>0 or @retcode<>0  return (1)
  24119.     
  24120.     exec ('grant exec on ' + @ins_procname + ' to public')
  24121.     set @command = 'sp_MSmakeupdateproc ' + QUOTENAME(@objectname) + ' , ' + QUOTENAME(@ownername) + ' , ' + @upd_procname + ', [' + convert(nchar(36), @pubid) + ']'
  24122.     exec @retcode = master..xp_execresultset @command, @dbname
  24123.     if @@ERROR<>0 OR @retcode<>0 
  24124.         begin
  24125.             return (1)
  24126.         end
  24127.     exec @retcode = dbo.sp_MS_marksystemobject  @upd_procname 
  24128.     if @@ERROR<>0 or @retcode<>0 return (1)
  24129.     exec ('grant exec on ' + @upd_procname + ' to public')
  24130.     if @@ERROR<>0 return (1)
  24131.     set @command= 'SET ANSI_NULLS ON SET QUOTED_IDENTIFIER ON'
  24132.     exec (@command)
  24133.     if @@ERROR<>0 return (1)
  24134.     set @command = 'sp_MSmakeselectproc ' + QUOTENAME(@objectname) + ' , ' + QUOTENAME(@ownername)+ ' , ' + @sel_procname + ', [' + convert(nchar(36), @pubid) + ']'
  24135.     exec @retcode = master..xp_execresultset @command, @dbname
  24136.     if @@ERROR<>0 or @retcode<>0
  24137.         begin
  24138.             return (1)
  24139.         end
  24140.     exec @retcode = dbo.sp_MS_marksystemobject  @sel_procname 
  24141.     if @@ERROR<>0 or @retcode<>0 return (1)
  24142.     exec ('grant exec on ' + @sel_procname + ' to public')
  24143.     if @@ERROR<>0 return (1)
  24144.  
  24145.     if @sync_objid <> 0 
  24146.         begin
  24147.  
  24148.             select @ownername = user_name(uid), @viewname = name from sysobjects 
  24149.                 where id = @sync_objid 
  24150.         select @rgcol = QUOTENAME(name) from syscolumns where id = @objid and
  24151.                 ColumnProperty(id, name, 'isrowguidcol') = 1
  24152.         
  24153.         exec @retcode=dbo.sp_MSmakeviewproc @viewname, @ownername, @view_selprocname, @rgcol, @objid
  24154.         if @@ERROR<>0 or @retcode<>0
  24155.             return (1)
  24156.         end
  24157.     else
  24158.         set @view_selprocname = ''
  24159.  
  24160.     --to be consistent with upgrade code by checking snapshot_ready>0
  24161.     if @snapshot_ready>0 and @conflict_table is not NULl
  24162.         begin
  24163.             exec @retcode = dbo.sp_MSguidtostr @artid, @guidstr out
  24164.             if @@ERROR <>0 OR @retcode <>0 return (1)
  24165.  
  24166.             exec @retcode = dbo.sp_MSguidtostr @pubid, @pubidstr out
  24167.             if @@ERROR <>0 OR @retcode <>0 return (1)
  24168.  
  24169.             select @conflict_proc = 'sp_cft_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16)
  24170.  
  24171.             exec @retcode=sp_MSuniqueobjectname @conflict_proc , @conflict_proc output
  24172.             if @@ERROR <> 0 OR @retcode <> 0 
  24173.                 return(1)
  24174.             set @dbname = db_name()
  24175.             set @command = 'sp_MSmakeconflictinsertproc ' + QUOTENAME(@conflict_table) + ' , ' + QUOTENAME(@ownername) + ' , ' + @conflict_proc  + ' , ' + convert(nvarchar,@objid) 
  24176.  
  24177.             set @command = @command    + ', [' + convert(nchar(36), @pubid) + ']'
  24178.             exec @retcode = master..xp_execresultset @command, @dbname
  24179.             if @@ERROR<>0 OR @retcode<>0 
  24180.             begin
  24181.                 return (1)
  24182.             end
  24183.             exec @retcode = dbo.sp_MS_marksystemobject  @conflict_proc 
  24184.             if @@ERROR<>0 or @retcode<>0  return (1)
  24185.  
  24186.             exec ('grant exec on ' + @conflict_proc + ' to public')
  24187.             if @@ERROR<>0 return (1)
  24188.             update sysmergearticles set ins_conflict_proc = @conflict_proc where artid = @artid and pubid=@pubid
  24189.         end
  24190.     -- update articles to set the names
  24191.     update sysmergearticles set insert_proc = @ins_procname, update_proc = @upd_procname ,
  24192.         select_proc = @sel_procname, view_sel_proc = @view_selprocname
  24193.         where artid = @artid and pubid = @pubid
  24194.     IF @@ERROR<>0 return (1)
  24195.     return (0)
  24196. go
  24197. exec dbo.sp_MS_marksystemobject sp_MSsetartprocs
  24198. go
  24199. grant exec on dbo.sp_MSsetartprocs to public
  24200. go
  24201. SET ANSI_NULLS OFF 
  24202. GO
  24203. raiserror('Creating procedure sp_MSmakesystableviews', 0,1)
  24204. GO
  24205.  
  24206. -- Used by snapshot
  24207. create procedure sp_MSmakesystableviews (
  24208.     @publication sysname,
  24209.     @dynamic_snapshot_views_table_name sysname = null
  24210.     )
  24211. AS
  24212.     declare @guidstr         nvarchar(40)
  24213.     declare @pubid          uniqueidentifier
  24214.     declare @contentsview     sysname 
  24215.     declare @tombstoneview     sysname
  24216.     declare @genhistoryview    sysname
  24217.     declare @filtersview    sysname
  24218.     declare @piece            nvarchar(4000)
  24219.     declare @retcode smallint
  24220.     declare @dbname            sysname
  24221.     declare @art_count        int
  24222.     declare @skip_ctsv         int
  24223.     declare    @command        nvarchar(500)
  24224.     declare @dynamic_filters bit
  24225.     declare @view_creation_command nvarchar(4000)
  24226.     declare @newid          uniqueidentifier
  24227.  
  24228.     /*
  24229.     ** Check to see if current publication has permission
  24230.     */
  24231.     exec @retcode=sp_MSreplcheck_publish
  24232.     if @retcode<>0 or @@ERROR<>0 return (1)
  24233.     set @skip_ctsv = 0
  24234.     select @pubid = pubid, @dynamic_filters = dynamic_filters from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name()
  24235.     if @pubid is null
  24236.         BEGIN
  24237.             RAISERROR (20026, 16, -1, @publication)
  24238.             RETURN (1)
  24239.         END
  24240.     select @art_count=count(*) from sysmergearticles where pubid=@pubid
  24241.     if @art_count > 253
  24242.         set @skip_ctsv=1
  24243.     select @newid = newid()
  24244.     create table #temp_table_for_systable_view(contentsview sysname, tombstoneview sysname NULL, genhistoryview sysname NULL, filtersview sysname NULL)
  24245.     exec @retcode = dbo.sp_MSguidtostr @newid, @guidstr out
  24246.     if @@ERROR<>0 OR @retcode<>0 return (1)
  24247.     select @contentsview = 'cont' + @guidstr
  24248.     select @tombstoneview = 'ts' + @guidstr
  24249.     select @genhistoryview = 'gh' + @guidstr
  24250.     select @filtersview = 'filt' + @guidstr
  24251.  
  24252.     set @guidstr = '''' + convert(nchar(36), @pubid) + ''''
  24253.     
  24254.     exec @retcode = dbo.sp_MSuniqueobjectname @tombstoneview, @tombstoneview out
  24255.     if @@ERROR<>0 OR @retcode<>0 return (1)
  24256.     exec @retcode = dbo.sp_MSuniqueobjectname @contentsview, @contentsview out
  24257.     if @@ERROR<>0 OR @retcode<>0 return (1)
  24258.     exec @retcode = dbo.sp_MSuniqueobjectname @genhistoryview, @genhistoryview out
  24259.     if @@ERROR<>0 OR @retcode<>0 return (1)
  24260.     exec @retcode = dbo.sp_MSuniqueobjectname @filtersview, @filtersview out
  24261.     if @@ERROR<>0 OR @retcode<>0 return (1)
  24262.     
  24263.     insert #temp_table_for_systable_view values(@contentsview,@tombstoneview,@genhistoryview,@filtersview)
  24264.  
  24265.     -- skip cts view if MSmerge_Contents contains zero rows
  24266.     if not exists (select * from MSmerge_contents)
  24267.         select @skip_ctsv = 1
  24268.         
  24269.     if @skip_ctsv = 0
  24270.     begin
  24271.         /* generate view for MSmerge_contents qualified by the pubid */
  24272.         /* For dynamically filtered publication, security check is performed in
  24273.            the sync view of the base table */
  24274.         set @command = 'sp_MSmakectsview ' + QUOTENAME(@publication) + ' , ' + @contentsview + ' , ' + COALESCE(QUOTENAME(@dynamic_snapshot_views_table_name) collate database_default, N'null' collate database_default) 
  24275.         set @dbname = db_name()
  24276.  
  24277.         exec @retcode = master..xp_execresultset @command, @dbname
  24278.         if @@ERROR<>0 OR @retcode <>0 
  24279.             return (1)
  24280.     end
  24281.     else
  24282.     begin
  24283.         exec('create view ' + @contentsview + ' as select * from MSmerge_contents where 1 = 2')
  24284.         if @@ERROR<>0
  24285.             return (1)
  24286.     end
  24287.     /* 
  24288.     ** generate the view for dbo.MSmerge_tombstone. In SP2 and Shiloh, the change was made to make the view 
  24289.     ** return 0 rows since it is unnecessary and expensive to propagate the tombstones.
  24290.     ** In order to leave all the other moving parts unchanged, we decided to let the view 
  24291.     ** return 0 rows.
  24292.     */
  24293.     select @view_creation_command = 'create view ' + @tombstoneview + ' as select * from dbo.MSmerge_tombstone where 1= 2 and
  24294.             tablenick in (select nickname from sysmergearticles where pubid = ' +
  24295.             @guidstr + ')'
  24296.  
  24297.     if @dynamic_filters = 1
  24298.     begin
  24299.         select @view_creation_command = @view_creation_command + ' and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'
  24300.     end
  24301.  
  24302.     exec (@view_creation_command)
  24303.     if @@ERROR <>0 
  24304.         begin
  24305.             return (1)
  24306.         end
  24307.  
  24308.     select @view_creation_command = 'create view ' + @genhistoryview + '(guidsrc, guidlocal, pubid, generation,
  24309.             art_nick, nicknames, coldate) as select DISTINCT gh.guidsrc, gh.guidlocal, CONVERT(uniqueidentifier, ' 
  24310.             + @guidstr + '), gh.generation, gh.art_nick, gh.nicknames, gh.coldate  from dbo.MSmerge_genhistory as gh
  24311.             where gh.guidlocal <> ''00000000-0000-0000-0000-000000000000'' and 
  24312.                   (gh.art_nick = 0 or gh.art_nick is NULL or gh.art_nick in (select nickname from sysmergearticles where pubid = ' +    @guidstr + ')) and
  24313.                   not exists (select * from dbo.MSmerge_genhistory where guidsrc=gh.guidsrc and generation>gh.generation)'
  24314.     if @dynamic_filters = 1
  24315.     begin
  24316.         select @view_creation_command = @view_creation_command + ' and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'
  24317.     end
  24318.  
  24319.     exec (@view_creation_command)
  24320.     if @@ERROR <>0
  24321.         begin
  24322.             return (1)
  24323.         end
  24324.  
  24325.     select @view_creation_command = 'create view ' + @filtersview + ' as select * from sysmergesubsetfilters where pubid = ' +
  24326.             @guidstr
  24327.  
  24328.     if @dynamic_filters = 1
  24329.     begin
  24330.         select @view_creation_command = @view_creation_command + ' and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)'
  24331.     end
  24332.  
  24333.     exec (@view_creation_command)
  24334.     if @@ERROR <>0
  24335.         begin
  24336.             return (1)
  24337.         end
  24338.  
  24339.     if @dynamic_filters = 1
  24340.     begin
  24341.         exec ('grant select on ' + @contentsview + ' to public')
  24342.         if @@error<>0 return(1)
  24343.         exec ('grant select on ' + @tombstoneview + ' to public')
  24344.         if @@error<>0 return(1)
  24345.         exec ('grant select on ' + @genhistoryview + ' to public')
  24346.         if @@error<>0 return(1)
  24347.         exec ('grant select on ' + @filtersview + ' to public')            
  24348.         if @@error<>0 return(1)
  24349.     end
  24350.  
  24351.     set nocount on
  24352.     /* we only generate per-article contents view for static publications */
  24353.     if @dynamic_filters=0
  24354.         begin
  24355.             exec @retcode = sp_MSgettablecontents @pubid
  24356.             if @@ERROR<>0 OR @retcode <>0 return (1)
  24357.          end
  24358.     exec('select * from #temp_table_for_systable_view ')
  24359.     drop table #temp_table_for_systable_view
  24360.  
  24361.     return (0)
  24362. go
  24363. exec dbo.sp_MS_marksystemobject sp_MSmakesystableviews
  24364. go
  24365. grant exec on dbo.sp_MSmakesystableviews to public
  24366. go
  24367.  
  24368.  
  24369. raiserror('Creating procedure sp_MSgetchangecount', 0,1)
  24370. GO
  24371.  
  24372. create procedure sp_MSgetchangecount(
  24373.     @startgen     int,
  24374.      @changes     int output,
  24375.      @updates     int output,
  24376.      @deletes     int output) as
  24377.     
  24378.     declare @retcode int
  24379.     
  24380.     -- security check
  24381.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck
  24382.     if @@error <> 0 or @retcode <> 0
  24383.         return 1
  24384.  
  24385.     select @deletes = count(*) from dbo.MSmerge_tombstone where generation = 0 or generation > @startgen
  24386.     select @updates = count(*) from dbo.MSmerge_contents where generation = 0 or generation > @startgen
  24387.     select @changes = @updates + @deletes
  24388.     return (0)        
  24389. go
  24390.  
  24391. exec dbo.sp_MS_marksystemobject sp_MSgetchangecount
  24392. go
  24393. grant exec on dbo.sp_MSgetchangecount to public
  24394.  
  24395. raiserror('Creating procedure sp_MSbelongs', 0,1)
  24396. GO
  24397.  
  24398. -- Modify temp table. No security check needed.
  24399. create procedure sp_MSbelongs
  24400.     @publisher        sysname,
  24401.     @publisher_db    sysname,
  24402.     @publication     sysname,
  24403.     @tablenick        int,
  24404.     @rowguid        uniqueidentifier,
  24405.     @retval            int output,
  24406.     @nested         int = 0
  24407. AS
  24408.     declare @artid uniqueidentifier
  24409.     declare @join_guid uniqueidentifier
  24410.     declare @last_joinid int
  24411.     declare @join_id int
  24412.     declare @join_nick int
  24413.     declare @probe_id int
  24414.     declare @last_probe int
  24415.     declare @join_nickstr nvarchar(10)
  24416.     declare @pubid uniqueidentifier
  24417.     declare @guidstring nvarchar(38)
  24418.     declare @subset_filter nvarchar(4000)
  24419.     declare @tablename nvarchar(266)
  24420.     declare @join_table nvarchar(266)
  24421.     declare @boolean nvarchar(4000)
  24422.     declare @retcode smallint
  24423.     
  24424.     select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
  24425.  
  24426.     /* Check for case of all rows  - do I trust subset_type ? */
  24427.     select @boolean = subset_filterclause, @artid = artid from sysmergearticles where
  24428.         pubid = @pubid and nickname = @tablenick
  24429.  
  24430.     if ((@boolean is null or @boolean = ' ') and not exists
  24431.         (select * from sysmergesubsetfilters where art_nickname = @tablenick))
  24432.         begin
  24433.         set @retval = 0
  24434.         return
  24435.         end
  24436.     if @nested = 0
  24437.         begin
  24438.         create table #found (flag int NOT NULL)
  24439.         create table #probe (probe_id int identity NOT NULL, tablenick int NOT NULL, 
  24440.                 rowguid uniqueidentifier ROWGUIDCOL default newid() not null, tested int NOT NULL)
  24441.         insert into #found values (0)
  24442.         set @last_probe = 0
  24443.         end
  24444.     else
  24445.         begin
  24446.         select @last_probe = max(probe_id) from #probe
  24447.         end
  24448.  
  24449.     /* pubid is already available */
  24450.     
  24451.     exec @retcode = dbo.sp_MStablenamefromnick @tablenick, @tablename out, @pubid
  24452.  
  24453.     if  @@ERROR<>0 or @retcode<>0 return (1) 
  24454.     set @guidstring = '''' + convert(nchar(36), @rowguid) + ''''
  24455.  
  24456.     /* If there is boolean filter, check for it being satisfied */
  24457.     if @boolean is not null and @boolean <> ' '
  24458.         begin
  24459.         exec ('if exists (select * from ' + @tablename + ' where rowguidcol = ' +
  24460.             @guidstring + ' and (' + @boolean + ')) update #found set flag = 1')
  24461.         if @@ERROR<>0 return (1)
  24462.         select @retval = flag from #found
  24463.         if @retval = 1 goto EndLabel
  24464.         end
  24465.     
  24466.     /* Loop over join filters, populating #probe */
  24467.     select @join_id = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and art_nickname = @tablenick
  24468.     while @join_id is not null
  24469.         begin
  24470.         select @boolean = join_filterclause, @join_nick = join_nickname from sysmergesubsetfilters where pubid = @pubid and join_filterid = @join_id
  24471.         exec @retcode = dbo.sp_MStablenamefromnick @join_nick, @join_table out, @pubid
  24472.         if @@ERROR<>0 or @retcode<>0 return (1)
  24473.         set @join_nickstr = convert(nchar(10), @join_nick)
  24474.  
  24475.         /* execute a query to put these into the #probe table */
  24476.         exec ('insert into #probe (tablenick, rowguid, tested) select distinct ' + @join_nickstr + 
  24477.             ', ' + @join_table + '.rowguidcol, 0 from ' + @tablename + ', ' + @join_table + '   
  24478.             where ' + @tablename + '.rowguidcol = ' + @guidstring + ' and (' + @boolean + ')
  24479.             and not exists (select * from #probe where tablenick = ' + @join_nickstr + 
  24480.             ' and rowguidcol = ' + @join_table + '.rowguidcol) ' )
  24481.         if @@ERROR<>0 
  24482.             begin
  24483.                 return (1)
  24484.             end    
  24485.  
  24486.         /* get to next join filter and repeat */
  24487.         set @last_joinid = @join_id
  24488.         select @join_id = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and art_nickname = @tablenick and join_filterid > @last_joinid
  24489.         end
  24490.     /* Loop over probe, making recursive call */
  24491.     select @probe_id = min(probe_id) from #probe where probe_id > @last_probe and tested = 0
  24492.     while @probe_id is not null
  24493.         begin
  24494.         select @join_nick = tablenick, @join_guid = rowguidcol from #probe where probe_id = @probe_id
  24495.         set @last_probe = @probe_id
  24496.  
  24497.         /* update tested flag on this row so we don't try it again while recursing */
  24498.         update #probe set tested = 1 where probe_id = @probe_id
  24499.     
  24500.         /* Make recursive call. If it belongs, we are done. */
  24501.         exec @retcode = dbo.sp_MSbelongs @publisher, @publisher_db, @publication, @join_nick, @join_guid, @retval output, 1
  24502.         if @@ERROR<>0 OR @retcode<>0
  24503.             begin
  24504.                 return (1)
  24505.             end
  24506.  
  24507.         if @retval = 1 goto EndLabel
  24508.         /* get next probe_id and repeat */
  24509.         select @probe_id = min(probe_id) from #probe where probe_id > @last_probe and tested = 0
  24510.         end
  24511.  
  24512.     /* All Done, delete temps if not nested */
  24513. EndLabel:
  24514.     if @nested = 0
  24515.         begin
  24516.         drop table #found
  24517.         drop table #probe
  24518.         end
  24519.     return
  24520.  
  24521. go
  24522.  
  24523. exec dbo.sp_MS_marksystemobject sp_MSbelongs
  24524. go
  24525.  
  24526. raiserror('Creating procedure sp_MSexpandbelongs', 0,1)
  24527. GO
  24528.  
  24529. -- Modify temp table. No security check needed.
  24530. create procedure sp_MSexpandbelongs
  24531.     @pubid         uniqueidentifier
  24532. AS
  24533.     declare @filterid    int
  24534.     , @retval            int
  24535.     , @expand_proc        sysname
  24536.     , @command            nvarchar(4000)
  24537.     , @retcode            int
  24538.     
  24539.     /* We iterate over the join filters */
  24540.     --select @filterid = min(flag) from #belong
  24541.     select @command = N'select @filterid = min(join_filterid) from dbo.sysmergesubsetfilters where pubid = @pubid and
  24542.             exists (select * from #belong where tablenick = join_nickname and flag < join_filterid and skipexpand = 0)'
  24543.     exec @retcode = sp_executesql @command, N'@filterid int output, @pubid uniqueidentifier', 
  24544.                                             @filterid = @filterid output, @pubid = @pubid
  24545.     if @@error <> 0 or @retcode <> 0 return 1
  24546.     
  24547.     while (@filterid is not null)
  24548.     begin
  24549.         select @expand_proc = expand_proc from dbo.sysmergesubsetfilters where pubid = @pubid and
  24550.                 join_filterid = @filterid
  24551.         exec @retval = @expand_proc @belong = 1
  24552.         if @@error<>0 or @retval <> 0 return (1)
  24553.         select @command = N'select @filterid = min(join_filterid) from dbo.sysmergesubsetfilters where pubid = @pubid and
  24554.             exists (select * from #belong where tablenick = join_nickname and flag < join_filterid and skipexpand = 0)'
  24555.         exec @retcode = sp_executesql @command, N'@filterid int output, @pubid uniqueidentifier', 
  24556.                                             @filterid = @filterid output, @pubid = @pubid
  24557.         if @@error <> 0 or @retcode <> 0 return 1
  24558.     end
  24559.         
  24560.     return (0)
  24561. go
  24562. exec dbo.sp_MS_marksystemobject sp_MSexpandbelongs
  24563. go
  24564.  
  24565. raiserror('Creating procedure sp_MSexpandnotbelongs', 0,1)
  24566. GO
  24567.  
  24568. -- Modify temp table. No security check needed.
  24569. create procedure sp_MSexpandnotbelongs
  24570.     @pubid         uniqueidentifier
  24571. AS
  24572.     declare @filterid         int
  24573.     , @retval            int
  24574.     , @expand_proc    sysname
  24575.     , @command        nvarchar(4000)
  24576.     , @retcode        int
  24577.     
  24578.     /* We iterate over the join filters */
  24579.     --select @filterid = min(flag) from #notbelong
  24580.     select @command = N'select @filterid = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and
  24581.             exists (select * from #notbelong where tablenick = join_nickname and flag < join_filterid)'
  24582.     exec @retcode = sp_executesql @command, N'@filterid int output, @pubid uniqueidentifier', 
  24583.                                             @filterid = @filterid output, @pubid = @pubid
  24584.     if @@error <> 0 or @retcode <> 0 return 1
  24585.     
  24586.     while (@filterid is not null)
  24587.     begin
  24588.         select @expand_proc = expand_proc from sysmergesubsetfilters where pubid = @pubid and
  24589.                 join_filterid = @filterid
  24590.         exec @retval = @expand_proc @belong = 0
  24591.         if @@error<>0 or @retval <> 0 return (1)
  24592.         select @command = N'select @filterid = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and
  24593.             exists (select * from #notbelong where tablenick = join_nickname and flag < join_filterid)'
  24594.         exec @retcode = sp_executesql @command, N'@filterid int output, @pubid uniqueidentifier', 
  24595.                                             @filterid = @filterid output, @pubid = @pubid
  24596.         if @@error <> 0 or @retcode <> 0 return 1
  24597.     end
  24598.     
  24599.     return 0
  24600. go
  24601. exec dbo.sp_MS_marksystemobject sp_MSexpandnotbelongs
  24602. go
  24603.  
  24604. raiserror('Creating procedure sp_MSsetupbelongs_withoutviewproc', 0,1)
  24605. GO
  24606. create procedure sp_MSsetupbelongs_withoutviewproc
  24607.     @publisher            sysname,
  24608.     @publisher_db        sysname,
  24609.     @publication         sysname,
  24610.     @artnick            int
  24611. AS
  24612.     declare @temp_id int
  24613.     declare @artnickstr nvarchar(10)
  24614.     declare @retval int
  24615.     declare @tablenick int
  24616.     declare @rowguid uniqueidentifier
  24617.     declare @rowguidstr nvarchar(40)
  24618.     declare @partchangegen int
  24619.     declare @joinchangegen int
  24620.     declare @retcode smallint
  24621.     
  24622.     set @artnickstr = convert(nchar(10), @artnick)
  24623.  
  24624.     delete from #temp_cont
  24625.  
  24626.     if exists(select * from #genlist)
  24627.     begin
  24628.         exec ('insert into #temp_cont (tablenick, rowguid, partchangegen, joinchangegen) 
  24629.                 select tablenick, rowguid, partchangegen, joinchangegen from dbo.MSmerge_contents where
  24630.                 tablenick  = ' + @artnickstr + ' and generation in (select generation from #genlist)')
  24631.         if @@ERROR <>0
  24632.         begin
  24633.             return (1)
  24634.         end    
  24635.     end
  24636.     
  24637.     set @temp_id = 0
  24638.     select @temp_id = min(temp_id) from #temp_cont where temp_id > @temp_id
  24639.     while (@temp_id is not null)
  24640.     begin
  24641.         select    @tablenick = tablenick, @rowguid = rowguid,
  24642.                 @partchangegen = partchangegen, @joinchangegen = joinchangegen 
  24643.                 from #temp_cont where temp_id = @temp_id
  24644.         set @rowguidstr = '''' + convert(nchar(36), @rowguid) + ''''
  24645.         exec @retcode = dbo.sp_MSbelongs @publisher, @publisher_db,    @publication, @tablenick, @rowguid, @retval    output, 0
  24646.         if @@ERROR<>0 OR @retcode <>0
  24647.         begin
  24648.             return (1)
  24649.         end
  24650.  
  24651.         if @retval = 1
  24652.         begin
  24653.             insert into #belong (tablenick, rowguid, flag, skipexpand, partchangegen, joinchangegen) values
  24654.                     (@artnick, @rowguid, 0, 0, @partchangegen, @joinchangegen)
  24655.             if @@ERROR <>0 
  24656.             begin
  24657.                 return (1)
  24658.             end
  24659.         end
  24660.         select @temp_id = min(temp_id) from #temp_cont where temp_id > @temp_id
  24661.     end
  24662.  
  24663.     return 0
  24664. GO
  24665. exec dbo.sp_MS_marksystemobject sp_MSsetupbelongs_withoutviewproc
  24666. go
  24667. raiserror('Creating procedure sp_MSsetupnotbelongs', 0,1)
  24668. GO
  24669. create procedure sp_MSsetupnotbelongs
  24670. @artnick            int,
  24671. @before_view_objid    int,
  24672. @before_table_objid int,
  24673. @rgcol                sysname,
  24674. @commongen            int
  24675. AS
  24676.     declare @before_view_name sysname
  24677.     , @before_table_name sysname
  24678.     , @artnickstr nvarchar(10)
  24679.     , @commongenstr nvarchar(12)
  24680.     , @command nvarchar(4000)
  24681.     , @retcode int
  24682.     
  24683.     set @artnickstr = convert(nvarchar(10), @artnick)
  24684.     set @commongenstr = convert(nvarchar(12), @commongen)
  24685.     
  24686.     /* Put changes in #notbelong  that aren't in #belong and have a relevant partchangegen    */
  24687.     -- If publication has before image tables, we should screen changes using the before image tables
  24688.     --rowguid in (select ' + @rgcol + ' from ' + @before_view_name + ') and
  24689.     if @before_view_objid is not null
  24690.     begin
  24691.         set @before_view_name = OBJECT_NAME(@before_view_objid)
  24692.         set @before_table_name = OBJECT_NAME(@before_table_objid)
  24693.         execute ('insert into #notbelong (tablenick, rowguid, flag, partchangegen, joinchangegen)
  24694.                 select tablenick, rowguid, 0, partchangegen, joinchangegen
  24695.                 from #contents_subset
  24696.                 where partchangegen > ' + @commongenstr + ' 
  24697.                 and tablenick = ' + @artnickstr + ' 
  24698.                 and    (rowguid in (select ' + @rgcol + ' from ' + @before_view_name + ' where generation > ' + @commongenstr + ')
  24699.                 or (rowguid in (select ' + @rgcol + '  from ' + @before_table_name + ' where system_delete = 1 and generation > ' + @commongenstr + ')
  24700.                 and (rowguid not in (select ' + @rgcol + ' from ' + @before_view_name + ' where generation > ' + @commongenstr + '))))    
  24701.                 and rowguid not in (select rowguid from #belong) ')
  24702.         if @@ERROR <>0 
  24703.         begin
  24704.             return (1)
  24705.         end
  24706.             
  24707.         if exists (select * from #genlist)
  24708.         begin
  24709.             /* Add tombstones to ##notbelong */
  24710.             execute ('insert into #notbelong (tablenick, rowguid, flag, partchangegen, joinchangegen, type) 
  24711.                 select tablenick, rowguid,  0, generation, generation, type from
  24712.                 #tombstone_subset where tablenick = ' + @artnickstr + ' and
  24713.                 (type = 6 or rowguid in (select ' + @rgcol + ' from ' + @before_view_name + ' where generation > ' + @commongenstr + '))')
  24714.             if @@ERROR <>0
  24715.             begin
  24716.                 return (1)
  24717.             end
  24718.         end
  24719.     end
  24720.     else
  24721.     begin 
  24722.         select @command = N'insert into #notbelong (tablenick, rowguid, flag, partchangegen, joinchangegen)
  24723.             select tablenick, rowguid, 0, partchangegen, joinchangegen
  24724.                 from #contents_subset
  24725.                 where partchangegen > @commongen 
  24726.                 and tablenick = @artnick 
  24727.                 and rowguid not in (select rowguid from #belong)'
  24728.         exec @retcode = sp_executesql @command, N'@commongen int, @artnick int', @commongen=@commongen, @artnick=@artnick
  24729.         if @@error <> 0 or @retcode <> 0
  24730.         begin
  24731.             return (1)
  24732.         end
  24733.  
  24734.         select @command = N'if exists (select * from #genlist)
  24735.         begin
  24736.             insert into #notbelong (tablenick, rowguid, flag, partchangegen, joinchangegen, type) 
  24737.                 select tablenick, rowguid,  0, generation, generation, type from
  24738.                 #tombstone_subset where tablenick = @artnick
  24739.         end'
  24740.         
  24741.         exec @retcode = sp_executesql @command, N'@artnick int', @artnick=@artnick
  24742.         if @@error <> 0 or @retcode <> 0 
  24743.         begin
  24744.             return (1)
  24745.         end
  24746.     end
  24747.  
  24748.     return (0)
  24749. GO
  24750. exec dbo.sp_MS_marksystemobject sp_MSsetupnotbelongs
  24751. go
  24752.  
  24753. raiserror('Creating procedure sp_MSsetupworktables', 0,1)
  24754. GO
  24755.  
  24756. -- Modify temp table. No security check needed.
  24757. create procedure sp_MSsetupworktables
  24758.     @pubid                uniqueidentifier,
  24759.     @genlist             varchar(8000),
  24760.     @articlesoption        int,    -- 0=process all articles, 1=process this specific article (whose nickname is passed in @tablenickname), 2=all articles involved in join filters, 3=process all articles involved in part filters, 4=process articles whose nicknames have been passed in @nicknamelist.
  24761.     @tablenickname        int,
  24762.     @nicknamelist        varchar(8000),
  24763.     @mingen                int = 0,
  24764.     @maxgen                int = 0,
  24765.     @skipgenlist        varchar(8000) = NULL,
  24766.     @contents_subset_rowcount int OUTPUT,
  24767.     @tombstone_subset_rowcount int OUTPUT
  24768. AS
  24769.     
  24770.     declare @lengenlist int
  24771.     , @lenskipgenlist int
  24772.     , @command nvarchar(4000)
  24773.     , @retcode int
  24774.  
  24775.     -- put in a nickname with value 0 - This will match 
  24776.     -- gen history rows put in by downlevel subscribers 
  24777.     -- with art_nick = NULL 
  24778.     select @command = N'insert into #nicknames_to_process values (0)'
  24779.     exec @retcode = sp_executesql @command
  24780.     if @@error <> 0 or @retcode <> 0 return 1
  24781.  
  24782.     if (@articlesoption = 0)
  24783.     begin
  24784.         
  24785.         -- process all articles for this publication
  24786.         select @command = N'insert into #nicknames_to_process 
  24787.         select distinct nickname 
  24788.         from sysmergearticles a 
  24789.         where pubid = @pubid'
  24790.         exec @retcode = sp_executesql @command, N'@pubid uniqueidentifier', @pubid=@pubid
  24791.         if @@error <> 0 or @retcode <> 0 return 1
  24792.  
  24793.     end
  24794.     else if (@articlesoption = 1)
  24795.     begin
  24796.         
  24797.         --process only the article whose nickname has been passed-in
  24798.         select @command = N'insert into #nicknames_to_process values (@tablenickname)'
  24799.         exec @retcode = sp_executesql @command, N'@tablenickname int', @tablenickname=@tablenickname
  24800.         if @@error <> 0 or @retcode <> 0 return 1
  24801.         
  24802.     end
  24803.     else if (@articlesoption = 2)
  24804.     begin
  24805.         --process all articles with join filters (article could be on any side - left or right - of any join filter)
  24806.         select @command = N'insert into #nicknames_to_process 
  24807.         select distinct nickname 
  24808.         from sysmergearticles a 
  24809.         where pubid = @pubid 
  24810.         and exists (select * from sysmergesubsetfilters s 
  24811.                     where s.pubid = @pubid 
  24812.                     and (s.art_nickname = a.nickname or s.join_nickname = a.nickname))'
  24813.         exec @retcode = sp_executesql @command, N'@pubid uniqueidentifier', @pubid=@pubid
  24814.         if @@error <> 0 or @retcode <> 0 return 1            
  24815.     end
  24816.     else if (@articlesoption = 3)
  24817.     begin
  24818.     
  24819.         --process all articles with part filters but that don't have a join filter.
  24820.         select @command = N'insert into #nicknames_to_process 
  24821.         select distinct nickname 
  24822.         from sysmergearticles a 
  24823.         where pubid = @pubid 
  24824.         and datalength(subset_filterclause) > 1
  24825.         and not exists (select * from sysmergesubsetfilters s 
  24826.                     where s.pubid = @pubid 
  24827.                     and (s.art_nickname = a.nickname or s.join_nickname = a.nickname))'
  24828.         exec @retcode = sp_executesql @command, N'@pubid uniqueidentifier', @pubid=@pubid
  24829.         if @@error <> 0 or @retcode <> 0 return 1
  24830.     end
  24831.     else if (@articlesoption = 4)
  24832.     begin
  24833.         --process all articles whose nicknames have been passed into @nicknamelist
  24834.         if (@nicknamelist is not null and rtrim(ltrim(@nicknamelist)) <> '')
  24835.         begin
  24836.             execute ('insert into #nicknames_to_process select distinct nickname from sysmergearticles where nickname in (' + @nicknamelist + ')')
  24837.             if @@error <> 0 return 1
  24838.         end
  24839.     end
  24840.  
  24841.     -- Create index on #nicknames_to_process now that it has been populated. Creating it after data insertion is better because
  24842.     -- that generates the stats for the index. That helps in the insert into #contents_subset query. The other option was to 
  24843.     -- create the index, insert the data, and then update statistics.
  24844.     select @command = N'create unique index #nicknames_ind on #nicknames_to_process (nickname)'
  24845.     exec @retcode = sp_executesql @command
  24846.     if @@error <> 0 or @retcode <> 0 return 1
  24847.  
  24848.     if (@maxgen <> 0)
  24849.     begin
  24850.             
  24851.         select @command = N'insert into #genlist select distinct generation 
  24852.             from dbo.MSmerge_genhistory gh 
  24853.             join #nicknames_to_process np
  24854.             on isnull(gh.art_nick,0) = np.nickname and 
  24855.             gh.generation >= @mingen
  24856.             and gh.generation <= @maxgen'
  24857.         exec @retcode = sp_executesql @command, N'@mingen int, @maxgen int', @mingen=@mingen, @maxgen=@maxgen
  24858.         if @@error <> 0 or @retcode <> 0 return 1
  24859.  
  24860.         select @lengenlist = isnull(datalength(@genlist),0)
  24861.         select @lenskipgenlist = isnull(datalength(@skipgenlist),0)
  24862.  
  24863.         -- no need to do ltrim and rtrim on the @skipgenlist. sp_MSsetupbelongs already did that.
  24864.         if (@skipgenlist is not null and @skipgenlist <> '' and @lenskipgenlist <= @lengenlist)
  24865.         begin
  24866.             execute ('delete from #genlist where generation in (' + @skipgenlist + ')')
  24867.             if @@error <> 0 return 1
  24868.         end
  24869.         else if (@genlist is not null and @genlist <> '')
  24870.         begin
  24871.             -- gen 0 won't be in @genlist, so will get deleted because of the NOT IN.
  24872.             execute ('delete from #genlist where generation not in (' + @genlist + ')')
  24873.             if @@error <> 0 return 1
  24874.         end
  24875.     end
  24876.     else if (@genlist is not null and @genlist <> '')
  24877.     begin
  24878.         execute ('insert into #genlist select distinct generation from dbo.MSmerge_genhistory where
  24879.             (isnull(art_nick,0) in (select nickname from #nicknames_to_process)) and 
  24880.             generation in (' + @genlist + ') ')
  24881.         if @@error <> 0 return 1
  24882.     end
  24883.  
  24884.     -- Create index on #genlist now that it has been populated. Creating it after data insertion is better because
  24885.     -- that generates the stats for the index. That helps in the insert into #contents_subset query. The other option was to 
  24886.     -- create the index, insert the data, and then update statistics.
  24887.     select @command = N'create unique index #genlist_ind on #genlist (generation)'
  24888.     exec @retcode = sp_executesql @command
  24889.     if @@error <> 0 or @retcode <> 0 return 1
  24890.  
  24891.     if @maxgen is null
  24892.         select @maxgen = 0
  24893.  
  24894.     if @mingen is null
  24895.         select @mingen = 0
  24896.  
  24897.     if (@maxgen = 0)
  24898.     begin
  24899.         -- SQL 7.0 pull merge agents do not pass in @maxgen and @mingen, so the default is 0. 
  24900.         -- For them need to compute min and max. Note that we could do the same for 8.0 agents as well
  24901.         -- but 8.0 agents pass the min and max because they are used in the INSERT INTO #genlist query above
  24902.         -- when we don't have the #genlist table and all we have is the comma-separated @genlist string.
  24903.         select @command = N'select @mingen = min(generation), @maxgen = max(generation) from #genlist'
  24904.         exec @retcode = sp_executesql @command, N'@mingen int output, @maxgen int output', @mingen=@mingen output, @maxgen=@maxgen output
  24905.         if @@error <> 0 or @retcode <> 0 return 1
  24906.     end
  24907.  
  24908.     select @command = N'insert into #contents_subset (tablenick, rowguid, generation, partchangegen, joinchangegen) 
  24909.     select c.tablenick, c.rowguid, c.generation, c.partchangegen, c.joinchangegen
  24910.     from dbo.MSmerge_contents c 
  24911.     JOIN #nicknames_to_process a
  24912.     ON c.generation >= @mingen
  24913.     AND c.generation <= @maxgen
  24914.     AND c.tablenick = a.nickname
  24915.     JOIN #genlist g 
  24916.     ON c.generation = g.generation
  24917.     AND c.generation >= @mingen
  24918.     AND c.generation <= @maxgen
  24919.  
  24920.     UNION
  24921.     
  24922.     -- the rows retrieved below have a partition change that falls into the relevant generation range
  24923.     -- if we do not process them now, we would later on assume that the partition change has already been processed
  24924.     select c.tablenick, c.rowguid, c.generation, c.partchangegen, c.joinchangegen
  24925.     from dbo.MSmerge_contents c 
  24926.     JOIN #nicknames_to_process a
  24927.     ON c.partchangegen >= @mingen
  24928.     AND c.partchangegen <= @maxgen
  24929.     AND c.tablenick = a.nickname
  24930.     JOIN #genlist g 
  24931.     ON c.partchangegen = g.generation
  24932.     AND c.partchangegen >= @mingen
  24933.     AND c.partchangegen <= @maxgen
  24934.     
  24935.     select @contents_subset_rowcount = @@rowcount'
  24936.     
  24937.     exec @retcode = sp_executesql @command, N'@mingen int, @maxgen int, @contents_subset_rowcount int output', 
  24938.                                             @mingen=@mingen, @maxgen=@maxgen, @contents_subset_rowcount=@contents_subset_rowcount output
  24939.     if @@error <> 0 or @retcode <> 0 return 1
  24940.  
  24941.     select @command = N'insert into #tombstone_subset (tablenick, rowguid, type, generation)
  24942.     select t.tablenick, t.rowguid, t.type, t.generation
  24943.     from dbo.MSmerge_tombstone t
  24944.     JOIN #nicknames_to_process a
  24945.     ON t.generation >= @mingen
  24946.     AND t.generation <= @maxgen
  24947.     AND t.tablenick = a.nickname
  24948.     JOIN #genlist g
  24949.     ON t.generation = g.generation
  24950.     AND t.generation >= @mingen
  24951.     AND t.generation <= @maxgen
  24952.         
  24953.     select @tombstone_subset_rowcount = @@rowcount'
  24954.     
  24955.     exec @retcode = sp_executesql @command, N'@mingen int, @maxgen int, @tombstone_subset_rowcount int output', 
  24956.                                             @mingen=@mingen, @maxgen=@maxgen, @tombstone_subset_rowcount=@tombstone_subset_rowcount output
  24957.     if @@error <> 0 or @retcode <> 0 return 1
  24958.  
  24959.     select @command = N'create clustered index #ucind_contents_subset on #contents_subset (tablenick, rowguid) with FILLFACTOR = 100
  24960.     create clustered index #ucind_tombstone_subset on #tombstone_subset (tablenick, rowguid) with FILLFACTOR = 100
  24961.  
  24962.     delete #nicknames_to_process from #nicknames_to_process ntp
  24963.     where not exists (select tablenick from #contents_subset cs where cs.tablenick = ntp.nickname) 
  24964.     and not exists (select tablenick from #tombstone_subset ts where ts.tablenick = ntp.nickname) 
  24965.  
  24966.     -- remove the nickname with value 0 that we put in specially at the beginning of this proc.
  24967.     delete from #nicknames_to_process where nickname = 0'
  24968.     
  24969.     exec @retcode = sp_executesql @command
  24970.     if @@error <> 0 or @retcode <> 0 return 1
  24971.     
  24972.     return (0)
  24973. GO
  24974. exec dbo.sp_MS_marksystemobject sp_MSsetupworktables
  24975. go
  24976. raiserror('Creating procedure sp_MSsetupbelongs', 0,1)
  24977. GO
  24978.  
  24979. -- Modify temp table. No security check needed.
  24980. create procedure sp_MSsetupbelongs
  24981.     @publisher            sysname,
  24982.     @publisher_db        sysname,
  24983.     @publication         sysname,
  24984.     @genlist             varchar(8000),
  24985.     @commongen            int,
  24986.     @subissql            int,
  24987.     @articlesoption        int=0,    -- 0=process all articles, 1=process this specific article (whose nickname is passed in @tablenickname), 2=all articles involved in join filters, 3=process all articles involved in part filters, 4=process articles whose nicknames have been passed in @nicknamelist.
  24988.     @tablenickname        int=0,
  24989.     @handle_null_tables bit=0,     -- 0=caller cannot handle NULL ##belongs and ##notbelongs tables, 1=caller handles NULL ##belongs and ##notbelongs tables (post 8.0 Beta 2 version)
  24990.     @nicknamelist        varchar(8000) = NULL,
  24991.     @mingen                int = 0,
  24992.     @maxgen                int = 0,
  24993.     @skipgenlist        varchar(8000) = NULL,
  24994.     @belongsname sysname = NULL,
  24995.     @notbelongsname sysname = NULL
  24996.  
  24997. AS
  24998.     -- Do all DDL right upfront. 
  24999.  
  25000.     create table #genlist (generation int)
  25001.  
  25002.     create table #temp_cont (temp_id int identity NOT NULL, tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL,
  25003.             partchangegen int null, joinchangegen int null)
  25004.  
  25005.     create table #contents_subset(tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, generation int NOT NULL,
  25006.             partchangegen int NULL, joinchangegen int NULL)
  25007.     
  25008.     create table #tombstone_subset(tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, type tinyint NOT NULL, 
  25009.             generation int NOT NULL)
  25010.  
  25011.     create table #belong (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, flag int NOT NULL,
  25012.         partchangegen int null, joinchangegen int null, skipexpand bit NOT NULL)
  25013.  
  25014.     create table #notbelong (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL,
  25015.         flag int NOT NULL, partchangegen int null, joinchangegen int null, type tinyint default 5)
  25016.     create table #nicknames_to_process (nickname int)
  25017.     create index #indbelong on #belong (rowguid, tablenick)
  25018.     create index #indnbelong on #notbelong (tablenick, rowguid)
  25019.     
  25020.     declare @pubid uniqueidentifier
  25021.     , @retval int
  25022.     , @tablenick int
  25023.     , @rowguid uniqueidentifier
  25024.     , @rowguidstr nvarchar(40)
  25025.     , @artnick    int
  25026.     , @before_view_objid int
  25027.     , @before_table_objid int
  25028.     , @procname sysname
  25029.     , @artbaseobjid int
  25030.     , @rgcol nvarchar(255)
  25031.     , @maxfilterid int
  25032.     , @retcode smallint
  25033.     , @dynamic_join_cnt int
  25034.     , @contents_subset_rowcount int
  25035.     , @tombstone_subset_rowcount int
  25036.     , @belongsempty bit
  25037.     , @notbelongsempty bit
  25038.     , @command nvarchar(4000)
  25039.  
  25040.     -- trim spaces from the generation lists so that we don't have to use functions ltrim 
  25041.     -- and rtrim again and again later on.
  25042.     select @genlist = ltrim(rtrim(@genlist))
  25043.     select @skipgenlist = ltrim(rtrim(@skipgenlist))
  25044.     select @nicknamelist = ltrim(rtrim(@nicknamelist))
  25045.  
  25046.     set @rowguid = newid()
  25047.     select @rowguidstr = replace( convert( nvarchar(36), @rowguid ), '-', '' )
  25048.  
  25049.     -- check permissions
  25050.     select @pubid = pubid from dbo.sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db    
  25051.     if ({ fn ISPALUSER(@pubid) } <> 1)
  25052.     begin    
  25053.         RAISERROR (14126, 11, -1)
  25054.         return (1)
  25055.     end
  25056.  
  25057.     -- since the belongsname and notbelongsname names have guids appended to them generated using newid(), we can safely assume
  25058.     -- that the names are unique.
  25059.     -- in the case of 80 SP3 and higher these table names would have been created by the agent as local temp tables and 
  25060.     -- the table names would be passed in
  25061.     if (@belongsname is NULL)
  25062.     begin
  25063.         set @belongsname = '##belong' + @rowguidstr
  25064.         exec ('create table ' + @belongsname + ' (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL,
  25065.             generation int NULL, lineage varbinary(255) NULL, colv varbinary(2048) NULL)')
  25066.         if @@ERROR <>0 return (1)
  25067.     end
  25068.  
  25069.     if (@notbelongsname is NULL)
  25070.     begin
  25071.         set @notbelongsname = '##notbelong' + @rowguidstr
  25072.         exec ('create table ' + @notbelongsname + ' (bookmark int identity unique NOT NULL, tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL,
  25073.             generation int NULL, lineage varbinary(255) NULL, type tinyint NOT NULL)')
  25074.         if @@ERROR <>0 return (1)
  25075.     end
  25076.     
  25077.     -- Fully qualifying the proc avoids recompiles
  25078.     exec @retcode = dbo.sp_MSsetupworktables @pubid, @genlist, @articlesoption, @tablenickname, @nicknamelist,
  25079.                                         @mingen, @maxgen, @skipgenlist,
  25080.                                         @contents_subset_rowcount OUTPUT, @tombstone_subset_rowcount OUTPUT
  25081.  
  25082.     IF @@ERROR<>0 OR @retcode<>0 return (1)    
  25083.  
  25084.     if (@contents_subset_rowcount = 0 and @tombstone_subset_rowcount = 0)
  25085.         goto EXITPROC
  25086.  
  25087.     if (@articlesoption <> 1 and @articlesoption <> 3 and @articlesoption <> 4)
  25088.     begin
  25089.         select @dynamic_join_cnt = count(*) from 
  25090.             (select join_filterclause_spaces_stripped = 
  25091.             REPLACE(REPLACE(REPLACE(REPLACE(UPPER(join_filterclause collate SQL_Latin1_General_CP1_CS_AS), char(0x20),''), char(0x09),''), char(0x0D),''), char(0x0A),'')
  25092.             from dbo.sysmergesubsetfilters 
  25093.             where pubid = @pubid) 
  25094.             as sysmergesubsetfilters_temp
  25095.         where 
  25096.         sysmergesubsetfilters_temp.join_filterclause_spaces_stripped like '%USER[_]%NAME()%' or
  25097.         sysmergesubsetfilters_temp.join_filterclause_spaces_stripped like '%USER[_]%ID()%' or
  25098.         sysmergesubsetfilters_temp.join_filterclause_spaces_stripped like '%SESSION[_]USER%' or
  25099.         sysmergesubsetfilters_temp.join_filterclause_spaces_stripped like '%SYSTEM[_]USER%'
  25100.     end
  25101.     
  25102.     /* step 2 setup pass through dbo.MSmerge_contents */
  25103.     /* article with permanent views can be handled with bulk inserts */
  25104.     set @artnick = NULL
  25105.     
  25106.     /* Get first article, go into loop */
  25107.     select @command = N'select @artnick = min(nickname) from #nicknames_to_process'
  25108.     exec @retcode = sp_executesql @command, N'@artnick int output', @artnick = @artnick output
  25109.     if @@error <> 0 or @retcode <> 0 return 1
  25110.     
  25111.     while (@artnick is not null)
  25112.     begin
  25113.         select    @artbaseobjid = objid, @procname = view_sel_proc, @before_view_objid = before_view_objid,
  25114.                 @before_table_objid = before_image_objid 
  25115.                 from dbo.sysmergearticles 
  25116.                 where pubid = @pubid 
  25117.                 and nickname = @artnick
  25118.         /* Get name of rowguidcol. Aliasing doesn't work through a view. */
  25119.         select @rgcol = quotename(name) from dbo.syscolumns where id = @artbaseobjid and ColumnProperty(@artbaseobjid, name, 'isrowguidcol') = 1
  25120.  
  25121.         if (@procname is not null)
  25122.         begin
  25123.             -- Fully qualifying the proc avoids recompiles
  25124.             select @procname = 'dbo.' + quotename(@procname)
  25125.             exec @retcode = @procname @artnick
  25126.             if @@ERROR <>0 or @retcode <> 0
  25127.                 begin
  25128.                 return (1)
  25129.                 end
  25130.         end
  25131.         else
  25132.         begin
  25133.             -- Fully qualifying the proc avoids recompiles
  25134.             exec @retcode = dbo.sp_MSsetupbelongs_withoutviewproc @publisher, @publisher_db, @publication, @artnick        
  25135.             if @@ERROR <>0 or @retcode <> 0
  25136.                 return (1)
  25137.         end
  25138.  
  25139.         -- Fully qualifying the proc avoids recompiles
  25140.         exec @retcode = dbo.sp_MSsetupnotbelongs @artnick, @before_view_objid, @before_table_objid, @rgcol, @commongen
  25141.         if @@ERROR <>0 or @retcode <> 0
  25142.                 return (1)
  25143.  
  25144.         /* Move on to next article, repeat while loop */
  25145.         select @command = N'select @artnick = min(nickname) from #nicknames_to_process where nickname > @artnick '
  25146.         exec @retcode = sp_executesql @command, N'@artnick int output', @artnick = @artnick output
  25147.         if @@error <> 0 or @retcode <> 0 return 1
  25148.     end
  25149.  
  25150.     if (@articlesoption <> 1 and @articlesoption <> 3 and @articlesoption <> 4)
  25151.     begin
  25152.         /* Optimization: If joinchangegen and partchange are both null or < common gen,
  25153.         ** it is not necessary to expand #belong for that particular row.
  25154.         */
  25155.         
  25156.         select @maxfilterid = max(join_filterid) from dbo.sysmergesubsetfilters
  25157.  
  25158.         if @maxfilterid is not null
  25159.         begin
  25160.             select @command = 
  25161.             N'update #belong set flag = @maxfilterid, skipexpand = 1 where isnull(joinchangegen,0) <= @commongen and
  25162.                 isnull(partchangegen,0) <= @commongen'
  25163.             exec @retcode = sp_executesql @command, N'@maxfilterid int, @commongen int', @maxfilterid = @maxfilterid, @commongen = @commongen
  25164.             if @@error <> 0 or @retcode <> 0 return 1
  25165.             
  25166.             /* Expand the #belong temptable */
  25167.             exec @retcode = dbo.sp_MSexpandbelongs @pubid
  25168.  
  25169.             if @@ERROR<>0 OR @retcode<>0
  25170.                 begin
  25171.                 return (1)
  25172.                 end
  25173.         end
  25174.     end
  25175.  
  25176.     /* If subscriber is sql server, we don't have to expand belongs */
  25177.     if (@articlesoption <> 1 and @articlesoption <> 3 and @articlesoption <> 4) and (@subissql = 0 or @dynamic_join_cnt > 0)
  25178.     begin
  25179.         /* Expand the #notbelong temptable */
  25180.         exec dbo.sp_MSexpandnotbelongs @pubid
  25181.         if @@error<>0 return(1)
  25182.     end
  25183.  
  25184. EXITPROC:
  25185.         
  25186.     /* transfer rows from local temp to global temp */
  25187.  
  25188.     -- Could have used if not exists instead of the following but want to use the KEEP PLAN option which is not supported in the IF EXISTS 
  25189.     select @belongsempty = 0
  25190.     select @command = N'select @belongsempty = 1 where not exists (select * from #belong)'
  25191.     exec @retcode = sp_executesql @command, N'@belongsempty bit output', @belongsempty = @belongsempty output
  25192.     if @@error <> 0 or @retcode <> 0 return 1
  25193.     
  25194.     select @notbelongsempty = 0
  25195.     select @command = N'select @notbelongsempty = 1 where not exists (select * from #notbelong)'
  25196.     exec @retcode = sp_executesql @command, N'@notbelongsempty bit output', @notbelongsempty = @notbelongsempty output
  25197.     if @@error <> 0 or @retcode <> 0 return 1
  25198.  
  25199.     /* If there are no rows in #belong, then drop the global ##belongs so that we do not call sp_MSenumpartialchanges */
  25200.     if (@belongsempty = 1)
  25201.     begin
  25202.         /* Post SQL 8.0 Beta 2 agents pass this flag with value 1 since they can handle NULL belongs table name */
  25203.         if @handle_null_tables = 1
  25204.             begin
  25205.                 exec ('drop table ' + @belongsname)
  25206.                 select @belongsname = NULL
  25207.             end
  25208.     end
  25209.     else
  25210.     begin
  25211.         exec ('insert into ' + @belongsname + ' (tablenick, rowguid, generation, lineage, colv) 
  25212.                 select distinct b.tablenick, b.rowguid, c.generation, c.lineage, c.colv1 from
  25213.                 #belong b left outer join dbo.MSmerge_contents c  
  25214.                 on  c.tablenick = b.tablenick and c.rowguid = b.rowguid ')
  25215.  
  25216.         if @@ERROR <>0    
  25217.         begin
  25218.                     return (1)
  25219.         end
  25220.  
  25221.         -- this index will be useful in sp_MSenumpartialchanges
  25222.         exec ('create index nc1belongstable on ' + @belongsname + ' (tablenick, rowguid) with FILLFACTOR = 100')
  25223.         if @@ERROR <>0    
  25224.             return (1)
  25225.     end
  25226.             
  25227.     /* If there are no rows in #notbelong, then drop the global ##notbelongs so that we do not call sp_MSenumpartialchanges */
  25228.     if (@notbelongsempty = 1)
  25229.     begin
  25230.         /* Post SQL 8.0 Beta 2 agents pass this flag with value 1 since they can handle NULL notbelongs table name */
  25231.         if @handle_null_tables = 1
  25232.             begin
  25233.                 exec ('drop table ' + @notbelongsname)
  25234.                 select @notbelongsname = NULL
  25235.             end
  25236.     end
  25237.     else
  25238.     begin
  25239.         /* transfer rows from local temp to global temp */
  25240.         exec ('insert into ' + @notbelongsname + ' (tablenick, rowguid, generation, lineage, type) 
  25241.                 select distinct b.tablenick, b.rowguid, coalesce (c.generation, t.generation), coalesce(c.lineage, t.lineage), b.type from
  25242.                 #notbelong b left outer join dbo.MSmerge_contents c  
  25243.                  on  c.tablenick = b.tablenick and c.rowguid = b.rowguid
  25244.                 left outer join dbo.MSmerge_tombstone t on t.tablenick = b.tablenick and t.rowguid = b.rowguid order by b.tablenick DESC, b.rowguid ASC ')
  25245.         if @@ERROR <>0    
  25246.         begin
  25247.             return (1)
  25248.         end
  25249.  
  25250.         -- this index will be useful in sp_MSenumpartialdeletes
  25251.         exec ('create index nc1notbelongstable on ' + @notbelongsname + ' (tablenick DESC, rowguid) with FILLFACTOR = 100')
  25252.         if @@ERROR <>0    
  25253.             return (1)
  25254.         
  25255.  
  25256.     end
  25257.     
  25258.     if (@belongsempty = 1)
  25259.         select @belongsname, @notbelongsname, -1
  25260.     else
  25261.     begin
  25262.         if (@articlesoption = 1)
  25263.         begin
  25264.             select @belongsname, @notbelongsname, @tablenickname
  25265.         end
  25266.         else
  25267.         begin
  25268.             select @command = N'select distinct @belongsname, @notbelongsname, tablenick from #belong'
  25269.             exec @retcode = sp_executesql @command, N'@belongsname sysname, @notbelongsname sysname', @belongsname=@belongsname, @notbelongsname=@notbelongsname
  25270.             if @@error <> 0 or @retcode <> 0 return 1
  25271.         end
  25272.     end
  25273.  
  25274.     drop table #notbelong
  25275.     drop table #belong
  25276.     drop table #contents_subset
  25277.     drop table #tombstone_subset
  25278.     drop table #temp_cont 
  25279.     drop table #nicknames_to_process
  25280.     
  25281.     return (0)
  25282. go
  25283.  
  25284. exec dbo.sp_MS_marksystemobject sp_MSsetupbelongs
  25285. go
  25286. grant exec on dbo.sp_MSsetupbelongs to public
  25287. go
  25288.  
  25289. raiserror('Creating procedure sp_MSaddinitialarticle', 0,1)
  25290. GO
  25291.  
  25292. -- Called at the subscriber
  25293. CREATE PROCEDURE sp_MSaddinitialarticle(
  25294.     @article                sysname,         /* Name of the article */
  25295.     @artid                     uniqueidentifier,            /* Article ID */
  25296.     @pubid                     uniqueidentifier,            /* Publication ID */
  25297.     @nickname                int,                /* Article nickname */
  25298.     @column_tracking        int,                /* Does the article have column tracking ? */
  25299.     @status                    int,                /* Status of the article */
  25300.     @pre_creation_command    int = 0,             /* Precreate command of the article */
  25301.     @resolver_clsid            nvarchar(255) = NULL,/* Resolver module for the article */
  25302.     @insert_proc            nvarchar(255) = NULL,/* Insert sp for article */
  25303.     @update_proc            nvarchar(255) = NULL,/* Update sp for article */
  25304.     @select_proc            nvarchar(255) = NULL, /* Select SP for this article */
  25305.     @destination_object        sysname,            /* Destination object name */
  25306.     @missing_count            int             = NULL,    
  25307.     @missing_cols            varbinary(32) = NULL,
  25308.     @article_resolver        nvarchar(255) = NULL,
  25309.     @resolver_info            nvarchar(255) = NULL,
  25310.     @filter_clause            nvarchar(2000) = NULL,
  25311.     @excluded_count            int             = NULL,
  25312.     @excluded_cols            varbinary(32)    = NULL,
  25313.     @destination_owner        sysname         = NULL,
  25314.     @identity_support        int                = 0,
  25315.     @verify_resolver_signature int            = 0,                            /* 0=do not verify signature, 1=verify that signature is from trusted source, more values may be added later */
  25316.     @fast_multicol_updateproc bit            = 0,
  25317.     @published_in_tran_pub bit                = 0
  25318.     ) AS
  25319.     
  25320.     SET NOCOUNT ON
  25321.  
  25322.     declare @objid int
  25323.     declare @sub_missing_cols binary(32)
  25324.     declare @retcode int
  25325.     /*
  25326.     ** Check for subscribing permission
  25327.     */
  25328.     exec @retcode=sp_MSreplcheck_subscribe
  25329.     if @retcode<>0 or @@ERROR<>0 return (1)
  25330.     
  25331.     if (@artid is NULL)
  25332.         BEGIN
  25333.             RAISERROR (14057, 16, -1)
  25334.             RETURN (1)
  25335.         END
  25336.  
  25337.     /*
  25338.     ** The columns that do not belong to the partition at subscriber side are nothing but
  25339.     ** missing columns to the subscriber side - it just does not have them !
  25340.     ** For the same reason, the excluded ones from publisher does not mean anything to
  25341.     ** subscriber, which does not exclude anything for itself. We just reset to 0
  25342.     */
  25343.     select @missing_count = @missing_count + @excluded_count
  25344.     exec @retcode= master..xp_ORbitmap @missing_cols, @excluded_cols, @sub_missing_cols OUTPUT
  25345.     if @@error<>0 or @retcode<>0 return(1)
  25346.     
  25347.     if (@resolver_clsid='') select @resolver_clsid = NULL
  25348.     if (@filter_clause='') set @filter_clause = NULL
  25349.     
  25350.     /*
  25351.     ** Populate the local copy of sysmergearticles
  25352.     */
  25353.     if exists (select * from sysmergearticles where artid = @artid and pubid = @pubid )
  25354.         begin
  25355.             update sysmergearticles 
  25356.                 set name = @article,
  25357.                     artid = @artid,
  25358.                     pre_creation_command = pre_creation_command,
  25359.                     pubid = @pubid,
  25360.                     nickname = @nickname,
  25361.                     column_tracking = @column_tracking,
  25362.                     status    = @status,
  25363.                     resolver_clsid = @resolver_clsid,
  25364.                     insert_proc = @insert_proc,
  25365.                     update_proc =  @update_proc,
  25366.                     select_proc = @select_proc,
  25367.                     destination_object = @destination_object,
  25368.                     destination_owner = @destination_owner,
  25369.                     missing_col_count = @missing_count,
  25370.                     missing_cols = @sub_missing_cols,
  25371.                     article_resolver = @article_resolver,
  25372.                     resolver_info = @resolver_info,
  25373.                     subset_filterclause = @filter_clause,
  25374.                     excluded_col_count = 0,
  25375.                     excluded_cols = 0x00,
  25376.                     identity_support=@identity_support,
  25377.                     verify_resolver_signature = @verify_resolver_signature,
  25378.                     fast_multicol_updateproc = @fast_multicol_updateproc,
  25379.                     published_in_tran_pub = @published_in_tran_pub
  25380.                 where artid = @artid and pubid = @pubid
  25381.         end
  25382.     else
  25383.         begin
  25384.             select @objid = 0
  25385.             insert sysmergearticles (name, type, objid, sync_objid, artid, pre_creation_command, pubid, 
  25386.                 nickname, column_tracking, status, resolver_clsid, destination_owner,
  25387.                 insert_proc, update_proc, select_proc, destination_object, missing_col_count, missing_cols, 
  25388.                 article_resolver, resolver_info, subset_filterclause, excluded_col_count, excluded_cols, identity_support,
  25389.                 verify_resolver_signature, fast_multicol_updateproc, published_in_tran_pub)
  25390.             values (@article, 0x0a, @objid, @objid, @artid, @pre_creation_command, @pubid, 
  25391.                 @nickname, @column_tracking, @status, @resolver_clsid, @destination_owner,
  25392.                 @insert_proc, @update_proc, @select_proc, @destination_object, @missing_count, @sub_missing_cols, 
  25393.                 @article_resolver, @resolver_info, @filter_clause, 0, 0x00, @identity_support, @verify_resolver_signature, 
  25394.                 @fast_multicol_updateproc, @published_in_tran_pub)
  25395.         end
  25396.     IF @@ERROR <> 0
  25397.         BEGIN
  25398.         RAISERROR (14057, 16, -1)
  25399.         RETURN (1)
  25400.     END
  25401.  
  25402.  
  25403.     RETURN 0
  25404. go
  25405.  
  25406. exec dbo.sp_MS_marksystemobject sp_MSaddinitialarticle
  25407. go
  25408. grant exec on dbo.sp_MSaddinitialarticle to public
  25409. go
  25410.  
  25411. raiserror('Creating procedure sp_MSaddinitialschemaarticle', 0,-1)
  25412. go
  25413. CREATE PROCEDURE sp_MSaddinitialschemaarticle(
  25414.     @name                 sysname,
  25415.     @destination_object   sysname,
  25416.     @destination_owner    sysname,
  25417.     @artid                uniqueidentifier,
  25418.     @pubid                uniqueidentifier,
  25419.     @pre_creation_command tinyint,
  25420.     @status               int,
  25421.     @type                 tinyint
  25422. )as    
  25423. begin
  25424.     set nocount on
  25425.     
  25426.     declare @objid int
  25427.     declare @old_objid int
  25428.     declare @retcode int
  25429.     declare @qualified_name nvarchar(270)
  25430.  
  25431.     /*
  25432.     ** Security check
  25433.     */
  25434.     exec @retcode=sp_MSreplcheck_subscribe
  25435.     if @retcode<>0 or @@ERROR<>0 return(1)
  25436.     
  25437.     if (@artid is NULL)
  25438.     begin
  25439.         raiserror (14057, 16, -1)
  25440.         return 1
  25441.     end
  25442.  
  25443.     if @destination_owner is null or @destination_owner = ''
  25444.     begin
  25445.         select @destination_owner = user_name()
  25446.     end
  25447.  
  25448.     select @qualified_name = quotename(@destination_owner) + '.' + quotename(@destination_object)
  25449.  
  25450.     select @objid = object_id(@qualified_name)
  25451.  
  25452.     select @old_objid = null
  25453.     select @old_objid = objid from sysmergeschemaarticles 
  25454.      where artid = @artid
  25455.        and pubid = @pubid
  25456.  
  25457.     -- Update the objid field of all merge schema articles with the same article id
  25458.     update sysmergeschemaarticles 
  25459.         set objid = @objid 
  25460.             where artid = @artid
  25461.  
  25462.     -- Update the objid field of all transactional schema articles with the same article id or same old objid
  25463.     if @old_objid is not null and @objid <> @old_objid
  25464.     begin
  25465.         if exists (select * from sysobjects where name = 'sysschemaarticles')
  25466.         begin
  25467.             update sysschemaarticles 
  25468.                set objid = @objid 
  25469.              where objid = @old_objid
  25470.         end  
  25471.     end
  25472.  
  25473.     begin transaction
  25474.  
  25475.     if exists (select * from sysmergeschemaarticles where artid = @artid and pubid = @pubid)
  25476.     begin
  25477.         
  25478.  
  25479.         update dbo.sysmergeschemaarticles
  25480.            set name = @name,
  25481.                destination_object = @destination_object,
  25482.                destination_owner = @destination_owner,
  25483.                pre_creation_command = @pre_creation_command,
  25484.                status = @status,
  25485.                type = @type
  25486.          where artid = @artid
  25487.            and pubid = @pubid              
  25488.  
  25489.         if @@error<>0
  25490.         begin
  25491.             rollback transaction
  25492.             return 1
  25493.         end
  25494.  
  25495.     end
  25496.     else
  25497.     begin
  25498.  
  25499.         insert dbo.sysmergeschemaarticles
  25500.             (name, type, objid, artid, description, pre_creation_command, 
  25501.              pubid, status, creation_script, schema_option, destination_object,
  25502.              destination_owner)
  25503.         values 
  25504.             (@name, @type, @objid, @artid, NULL, @pre_creation_command,
  25505.              @pubid, @status, NULL, 0x0000000000000000, @destination_object,
  25506.              @destination_owner)
  25507.         if @@error<>0
  25508.         begin
  25509.             rollback transaction
  25510.             return 1
  25511.         end
  25512.         
  25513.     end
  25514.  
  25515.     exec @retcode = dbo.sp_MSmarkschemaobject @destination_object, @destination_owner
  25516.     if @@error<>0 or @retcode<>0
  25517.     begin
  25518.         rollback transaction
  25519.         return 1    
  25520.     end 
  25521.     commit transaction
  25522.  
  25523.     return 0
  25524. end
  25525. go
  25526. exec dbo.sp_MS_marksystemobject sp_MSaddinitialschemaarticle
  25527. go
  25528. grant exec on dbo.sp_MSaddinitialschemaarticle to public
  25529. go
  25530.  
  25531.  
  25532. raiserror('Creating procedure sp_MSaddinitialpublication', 0,1)
  25533. GO
  25534.  
  25535. CREATE PROCEDURE sp_MSaddinitialpublication(
  25536.     @publisher                sysname,
  25537.     @publisher_db             sysname,
  25538.     @publication            sysname,             /* Name of the publication */
  25539.     @description            nvarchar(255),         /* Description of the publication */
  25540.     @pubid                     uniqueidentifier,    /* Publication ID */
  25541.     @retention                int,                /* Retention period of the publication */
  25542.     @sync_mode                int,                /* Sync mode of the publication */
  25543.     @allow_push                int,                /* does publication allow push ? */
  25544.     @allow_pull                int,                /* does publication allow pull ? */
  25545.     @allow_anonymous        int,                /* does publication allow anonymous ? */
  25546.     @centralized_conflicts    int,                 /* publication does centralized conflicts ? */
  25547.     @status                    int,                 /* publication's status */
  25548.     @snapshot_ready            int,                 /* publication snapshto_ready flag ? */
  25549.     @enabled_for_internet    int,                 /* publication enabled_for_internet flag ? */
  25550.     @publication_type        int,                /* a full publication or a partial one */
  25551.     @conflict_retention        int = 60,                /* the retention period for conflict table */
  25552.     @allow_subscription_copy int = 0,                /* does publication allow subscription copies to sync ? */
  25553.     @allow_synctoalternate     int = 0,                /* does publication allow subscription to sync to alternates ? */
  25554.     @backward_comp_level    int = 10            /* default to 7.0 server */
  25555.     ) AS
  25556.     
  25557.     SET NOCOUNT ON
  25558.     declare @retcode             int
  25559.     declare @publisher_srvid     int
  25560.  
  25561.     select @publication = RTRIM(@publication)
  25562.     select @publisher_db = RTRIM(@publisher_db)
  25563.  
  25564.     /*
  25565.     ** Check for subscribing permission
  25566.     */
  25567.     exec @retcode=sp_MSreplcheck_subscribe
  25568.     if @retcode<>0 or @@ERROR<>0 return (1)
  25569.  
  25570.     select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
  25571.     if @publisher_srvid is NULL
  25572.         begin
  25573.         EXECUTE @retcode = dbo.sp_addserver @publisher, @duplicate_ok='duplicate_ok'
  25574.  
  25575.         IF @@error <> 0 OR @retcode <> 0
  25576.             BEGIN
  25577.                 RAISERROR (14042, 16, -1)
  25578.                 RETURN (1)
  25579.             END
  25580.         end                
  25581.  
  25582.     select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
  25583.     IF @publisher_srvid IS NULL
  25584.         BEGIN
  25585.             RAISERROR (14010, 16, -1)
  25586.             RETURN (1)
  25587.         END
  25588.     
  25589.     /*
  25590.     ** Populate the local copy of sysmergepublications
  25591.     */
  25592.     BEGIN TRAN
  25593.     save TRAN MSaddinitialpublication
  25594.     
  25595.     if exists (select * from sysmergepublications 
  25596.             where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db)
  25597.         begin 
  25598.             declare @pubid_local uniqueidentifier
  25599.  
  25600.             /* select the local pubid only if it has a valid parentid */
  25601.             select @pubid_local = pubid    from sysmergepublications 
  25602.                 where name = @publication and 
  25603.                     UPPER(publisher)=UPPER(@publisher) and 
  25604.                     publisher_db=@publisher_db
  25605.             if exists (select * from sysmergesubscriptions 
  25606.                 where pubid = @pubid and srvid = @publisher_srvid and db_name = @publisher_db)
  25607.                     begin
  25608.                         delete from sysmergesubscriptions 
  25609.                             where pubid = @pubid and srvid = @publisher_srvid and db_name = @publisher_db
  25610.                         IF @@ERROR <> 0
  25611.                             BEGIN
  25612.                                 RAISERROR (14057, 16, -1)
  25613.                                 goto FAILURE
  25614.                             END
  25615.                     end
  25616.             update sysmergesubscriptions SET pubid = @pubid where pubid = @pubid_local
  25617.             IF @@ERROR <> 0
  25618.                 BEGIN
  25619.                     RAISERROR (14057, 16, -1)
  25620.                     goto FAILURE
  25621.                 END
  25622.             if @pubid <> @pubid_local
  25623.                 delete from sysmergesubscriptions where subid = @pubid
  25624.                 
  25625.             update sysmergesubscriptions SET subid = @pubid where subid = @pubid_local
  25626.             IF @@ERROR <> 0
  25627.                 BEGIN
  25628.                     RAISERROR (14057, 16, -1)
  25629.                     goto FAILURE
  25630.                 END
  25631.             update sysmergesubscriptions    
  25632.                 SET partnerid = @pubid
  25633.                 where partnerid = @pubid_local
  25634.         
  25635.             IF @@ERROR <> 0
  25636.                 BEGIN
  25637.                     RAISERROR (14057, 16, -1)
  25638.                     goto FAILURE
  25639.                 END
  25640.             update sysmergepublications 
  25641.                 SET pubid = @pubid, 
  25642.                     name = @publication, 
  25643.                     description = @description, 
  25644.                     designmasterid = @pubid, 
  25645.                     retention = @retention, 
  25646.                     parentid = pubid, 
  25647.                     sync_mode = sync_mode, 
  25648.                     allow_push = @allow_push, 
  25649.                     allow_pull = @allow_pull, 
  25650.                     allow_anonymous = @allow_anonymous, 
  25651.                     centralized_conflicts = @centralized_conflicts,
  25652.                     status = @status,
  25653.                     snapshot_ready = @snapshot_ready,
  25654.                     enabled_for_internet = @enabled_for_internet,
  25655.                     publication_type = @publication_type,
  25656.                     conflict_retention = @conflict_retention,
  25657.                     allow_subscription_copy = @allow_subscription_copy, 
  25658.                     allow_synctoalternate = @allow_synctoalternate ,
  25659.                     backward_comp_level = @backward_comp_level
  25660.                 where name = @publication
  25661.                       and UPPER(publisher) = UPPER(@publisher)
  25662.                       and publisher_db = @publisher_db
  25663.         end
  25664.     else
  25665.         begin
  25666.             insert sysmergepublications(publisher, publisher_db,pubid, name, description, designmasterid, 
  25667.                 retention, parentid, sync_mode, allow_push, allow_pull, allow_anonymous, 
  25668.                 centralized_conflicts, status, snapshot_ready, enabled_for_internet, publication_type, 
  25669.                 conflict_retention, allow_subscription_copy, allow_synctoalternate, backward_comp_level)
  25670.             values(@publisher, @publisher_db, @pubid, @publication, @description, @pubid, 
  25671.                 @retention, @pubid, @sync_mode, @allow_push, @allow_pull, @allow_anonymous, 
  25672.                 @centralized_conflicts, @status, @snapshot_ready, @enabled_for_internet, @publication_type, 
  25673.                 @conflict_retention, @allow_subscription_copy, @allow_synctoalternate, @backward_comp_level)
  25674.         end
  25675.     IF @@ERROR <> 0
  25676.         BEGIN
  25677.             RAISERROR (14057, 16, -1)
  25678.             goto FAILURE
  25679.         END
  25680.     COMMIT TRAN
  25681.  
  25682.     RETURN (0)
  25683.  
  25684. FAILURE:
  25685.     /* UNDONE : This code is specific to 6.X nested transaction semantics */
  25686.     if @@TRANCOUNT > 0
  25687.     begin
  25688.         ROLLBACK TRANSACTION MSaddinitialpublication
  25689.         COMMIT TRANSACTION
  25690.     end
  25691.     RETURN (1)
  25692. go
  25693. exec dbo.sp_MS_marksystemobject sp_MSaddinitialpublication
  25694. go
  25695. grant exec on dbo.sp_MSaddinitialpublication to public
  25696. go
  25697.  
  25698. raiserror('Creating procedure sp_MSaddinitialsubscription', 0,1)
  25699. GO
  25700.  
  25701. CREATE PROCEDURE sp_MSaddinitialsubscription(
  25702.     @pubid                     uniqueidentifier,        /* Publication ID */
  25703.     @subid                     uniqueidentifier,          /* Subscription's replica ID */
  25704.     @partnerid                 uniqueidentifier,          /* Partner's replica ID */
  25705.     @subscriber                sysname,                 /* Subscriber server */
  25706.     @subscriber_db            sysname,                  /* Subscriber database */
  25707.     @subscriber_priority     real = 0.0,                 /* Subscriber priority */
  25708.     @subscriber_type        tinyint = 0,            /* Subscriber type - local, global, or anonymous */
  25709.     @subscription_type         int = 0,                /* Subscription type - push or pull */
  25710.     @sync_type                 tinyint = 2,            /* Subscription sync type 1 = no sync, 2 = automatic */
  25711.     @publication            sysname = NULL,            /* Publication Name */
  25712.     @distributor            sysname = NULL            /* Distributor */
  25713.     ) AS
  25714.     
  25715.     SET NOCOUNT ON
  25716.  
  25717.     /*
  25718.     ** Declarations.
  25719.     */
  25720.     DECLARE @local                 tinyint
  25721.     DECLARE @anonymous             tinyint
  25722.     DECLARE @subscriber_srvid    int
  25723.     DECLARE @subnickname        int
  25724.     DECLARE @active             tinyint
  25725.     DECLARE @retcode            int
  25726.     DECLARE    @subid_old            uniqueidentifier
  25727.  
  25728.     
  25729.     /* 
  25730.     ** Initializations
  25731.     */
  25732.     SET @local                 = 2
  25733.     SET @anonymous             = 3
  25734.     set @active             = 1 /* after this SP is called, the subscription is activated */
  25735.  
  25736.     select @subscriber_db = RTRIM(@subscriber_db)
  25737.     /*
  25738.     ** Check for subscribing permission
  25739.     ** It is called by merge agent at the publisher side
  25740.     ** subscriber side?
  25741.     */
  25742.     -- @pubid is not local
  25743.     if ({ fn ISPALUSER(@pubid) } <> 1)
  25744.     begin    
  25745.         RAISERROR (14126, 11, -1)
  25746.         return (1)
  25747.     end
  25748.  
  25749.     -- this gets executed at both publisher (for pull subscriptions) and at subscriber
  25750.     --  if server is not found use srvid of 0 for local srvid
  25751.     
  25752.     select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
  25753.     if @subscriber_srvid is null
  25754.         set @subscriber_srvid = 0
  25755.  
  25756.     begin tran
  25757.     save TRAN MSaddinitialsubscription    
  25758.         /*
  25759.         ** Populate the local copy of sysmergesubscriptions
  25760.         */
  25761.     if exists (select * from sysmergesubscriptions where subid = @subid)
  25762.             begin
  25763.                 update sysmergesubscriptions 
  25764.                     SET    subid = @subid,
  25765.                         datasource_type = 0,
  25766.                         datasource_path = NULL,
  25767.                         srvid = @subscriber_srvid,
  25768.                         db_name = @subscriber_db,
  25769.                         pubid = @pubid,
  25770.                         status = @active,
  25771.                         subscriber_type = @subscriber_type,
  25772.                         subscription_type =    @subscription_type,
  25773.                         priority = @subscriber_priority,
  25774.                         sync_type = @sync_type,
  25775.                         subscriber_server = @subscriber,
  25776.                         publication = @publication,
  25777.                         distributor = @distributor
  25778.                     where subid = @subid 
  25779.                             
  25780.                 IF @@ERROR <> 0
  25781.                     BEGIN
  25782.                         goto FAILURE
  25783.                     END
  25784.             end                    
  25785.                     
  25786.         if exists (select * from sysmergesubscriptions where srvid = @subscriber_srvid AND db_name = @subscriber_db AND pubid = @pubid)
  25787.             begin
  25788.                 select @subid_old = subid from sysmergesubscriptions where srvid = @subscriber_srvid AND db_name = @subscriber_db AND pubid = @pubid
  25789.                 update sysmergesubscriptions 
  25790.                     SET    subid = @subid,
  25791.                         datasource_type = 0,
  25792.                         datasource_path = NULL,
  25793.                         srvid = @subscriber_srvid,
  25794.                         db_name = @subscriber_db,
  25795.                         pubid = @pubid,
  25796.                         status = @active,
  25797.                         subscriber_type = @subscriber_type,
  25798.                         subscription_type =    @subscription_type,
  25799.                         priority = @subscriber_priority,
  25800.                         sync_type = @sync_type,
  25801.                         subscriber_server = @subscriber,
  25802.                         publication = @publication,
  25803.                         distributor = @distributor
  25804.                     where srvid = @subscriber_srvid AND db_name = @subscriber_db  AND pubid = @pubid
  25805.                             
  25806.                 IF @@ERROR <> 0
  25807.                     BEGIN
  25808.                         goto FAILURE
  25809.                     END
  25810.                 if (@subid_old IS NOT NULL)
  25811.                     begin
  25812.                         /*
  25813.                         **  Delete old row for subscriber from MSmerge_replinfo.
  25814.                         */
  25815.                         DELETE from MSmerge_replinfo where repid = @subid_old
  25816.                         IF @@ERROR <> 0
  25817.                             BEGIN
  25818.                                 goto FAILURE
  25819.                             END
  25820.  
  25821.                         EXECUTE @retcode = dbo.sp_MSgenreplnickname @subid, @subnickname output
  25822.                         if @@ERROR<>0 or @retcode<>0 goto FAILURE
  25823.                         
  25824.                         /*
  25825.                         **  Add new row for subscriber to MSmerge_replinfo.
  25826.                         */
  25827.                         INSERT INTO  MSmerge_replinfo(repid, replnickname)    
  25828.                             values (@subid, @subnickname) 
  25829.                         IF @@ERROR <> 0
  25830.                             BEGIN
  25831.                                 goto FAILURE
  25832.                             END
  25833.                     end                    
  25834.             end
  25835.         else
  25836.             begin
  25837.                 INSERT sysmergesubscriptions(subid,
  25838.                                           partnerid,
  25839.                                           datasource_type, 
  25840.                                           datasource_path, 
  25841.                                           srvid, 
  25842.                                           db_name, 
  25843.                                           pubid,
  25844.                                           status, 
  25845.                                           subscriber_type,
  25846.                                           subscription_type,
  25847.                                           priority, 
  25848.                                           sync_type, 
  25849.                                           description,
  25850.                                           login_name,
  25851.                                           subscriber_server,
  25852.                                           publication,
  25853.                                           distributor)
  25854.                     VALUES (@subid,
  25855.                             @partnerid,
  25856.                             0,
  25857.                             NULL,
  25858.                                @subscriber_srvid,
  25859.                               @subscriber_db,
  25860.                                @pubid,
  25861.                             @active,
  25862.                             @subscriber_type,
  25863.                             @subscription_type,
  25864.                             @subscriber_priority,
  25865.                             @sync_type, 
  25866.                             NULL, 
  25867.                             suser_sname(suser_sid()),
  25868.                             @subscriber,
  25869.                             @publication,
  25870.                             @distributor)
  25871.  
  25872.                 IF @@ERROR <> 0
  25873.                     BEGIN
  25874.                         goto FAILURE
  25875.                     END
  25876.  
  25877.                 /* Look for existing nickname from any other subscription */
  25878.                 select @subnickname = max(replnickname) from MSmerge_replinfo,
  25879.                      sysmergesubscriptions where repid = subid 
  25880.                          and srvid = @subscriber_srvid 
  25881.                          and    db_name = @subscriber_db
  25882.                 /* Generate a new replica nickname from the @subid */
  25883.                 if (@subnickname is null)
  25884.                     begin
  25885.                         EXECUTE @retcode = dbo.sp_MSgenreplnickname @subid, @subnickname output
  25886.                         if @@ERROR<>0 or @retcode<>0 goto FAILURE
  25887.                     end
  25888.                 /*
  25889.                 **  Add row for subscriber to MSmerge_replinfo.
  25890.                 */
  25891.                 INSERT INTO  MSmerge_replinfo(repid, replnickname)    
  25892.                     values (@subid, @subnickname) 
  25893.                 IF @@ERROR <> 0
  25894.                     BEGIN
  25895.                         goto FAILURE
  25896.                     END
  25897.             end                                        
  25898.  
  25899.  
  25900.     COMMIT TRAN            
  25901.     RETURN 0
  25902.  
  25903. FAILURE:
  25904.     /* UNDONE : This code is specific to 6.X nested transaction semantics */
  25905.     if @@TRANCOUNT > 0
  25906.     begin
  25907.         ROLLBACK TRANSACTION MSaddinitialsubscription
  25908.         COMMIT TRANSACTION
  25909.     end
  25910.     
  25911.     RAISERROR (14057, 16, -1)
  25912.     RETURN 1
  25913. go
  25914. exec dbo.sp_MS_marksystemobject sp_MSaddinitialsubscription
  25915. go
  25916. grant exec on dbo.sp_MSaddinitialsubscription to public
  25917. go 
  25918.  
  25919. raiserror('Creating procedure sp_MSmakearticleprocs', 0,1)
  25920. GO
  25921.  
  25922. create procedure sp_MSmakearticleprocs
  25923.     (@pubid uniqueidentifier, @artid uniqueidentifier)
  25924. as
  25925.     declare @ownername sysname
  25926.     declare @objectname sysname
  25927.     declare @ins_procname sysname
  25928.     declare @sel_procname sysname
  25929.     declare @upd_procname sysname
  25930.     declare @guidstr nvarchar(40)
  25931.     declare @trigname         sysname
  25932.     declare @objid int
  25933.     declare @dbname            sysname
  25934.     declare @command        nvarchar(1000)
  25935.     
  25936.     -- to be called after article is set up in a subscriber
  25937.     declare @retcode smallint
  25938.  
  25939.     /*
  25940.     ** Check for subscribing permission
  25941.     */
  25942.     exec @retcode=sp_MSreplcheck_subscribe
  25943.     if @retcode<>0 or @@ERROR<>0 return (1)
  25944.  
  25945.     select @objid = max(objid) from sysmergearticles where artid = @artid
  25946.     -- get owner name, and table name
  25947.     select @objectname = name, @ownername = user_name(uid)
  25948.         from sysobjects    where id = @objid
  25949.  
  25950.     -- get the  insert and update proc names from sys articles
  25951.     select @ins_procname = insert_proc, @upd_procname = update_proc, @sel_procname = select_proc
  25952.         from sysmergearticles where pubid = @pubid and artid = @artid
  25953.  
  25954.     if object_id(@ins_procname) is not NULL
  25955.     begin
  25956.         select @command = 'drop proc ' + quotename(@ins_procname)
  25957.         exec (@command)
  25958.         if @@ERROR<>0 
  25959.             return (1)
  25960.     end
  25961.  
  25962.     if object_id(@upd_procname) is not NULL
  25963.     begin
  25964.         select @command = 'drop proc ' + quotename(@upd_procname)
  25965.         exec (@command)
  25966.         if @@ERROR<>0
  25967.             return (1)
  25968.     end
  25969.  
  25970.     if object_id(@sel_procname) is not NULL
  25971.     begin
  25972.         select @command = 'drop proc ' + quotename(@sel_procname)
  25973.         exec (@command)
  25974.         if @@ERROR<>0
  25975.             return (1)
  25976.     end
  25977.  
  25978.     -- create the procs
  25979.     set @dbname = db_name()
  25980.     /* If procedure already exists because article in multiple pubs don't bother */
  25981.     if not exists (select * from sysobjects where name = @ins_procname and type = 'P')
  25982.         begin
  25983.         set @command = 'sp_MSmakeinsertproc ' + QUOTENAME(@objectname) + ' , ' + QUOTENAME(@ownername) + ' , ' + @ins_procname  + ', [' + convert(nchar(36), @pubid) + ']'
  25984.         exec @retcode = master..xp_execresultset @command, @dbname
  25985.         if @@ERROR<>0 OR @retcode <>0 return (1)
  25986.         exec @retcode = dbo.sp_MS_marksystemobject  @ins_procname 
  25987.         if @@ERROR<>0 OR @retcode <>0 return (1)
  25988.         select @command = 'grant exec on ' + quotename(@ins_procname) + ' to public'
  25989.         exec (@command)
  25990.         if @@ERROR<>0 return (1)
  25991.         end
  25992.  
  25993.     /* If procedure already exists because article in multiple pubs don't bother */
  25994.     if not exists (select * from sysobjects where name = @upd_procname and type = 'P')
  25995.         begin
  25996.         set @command = 'sp_MSmakeupdateproc ' + QUOTENAME(@objectname) + ' , ' + QUOTENAME(@ownername) + ' , ' + @upd_procname + ', [' + convert(nchar(36), @pubid) + ']'
  25997.         exec @retcode = master..xp_execresultset @command, @dbname
  25998.         if @@ERROR<>0 OR @retcode <>0 return (1)
  25999.         exec @retcode = dbo.sp_MS_marksystemobject  @upd_procname 
  26000.         if @@ERROR<>0 or @retcode <>0 return (1)
  26001.         select @command = 'grant exec on ' + quotename(@upd_procname) + ' to public'
  26002.         exec(@command)
  26003.         if @@ERROR<>0 return (1)
  26004.         end
  26005.         
  26006.     /* If procedure already exists because article in multiple pubs don't bother */
  26007.     if not exists (select * from sysobjects where name = @sel_procname and type = 'P')
  26008.         begin
  26009.         set @command = 'sp_MSmakeselectproc ' + QUOTENAME(@objectname) + ' , ' + QUOTENAME(@ownername) + ' , ' + @sel_procname + ', [' + convert(nchar(36), @pubid) + ']'
  26010.         exec @retcode = master..xp_execresultset @command, @dbname
  26011.         if @@ERROR<>0 or @retcode<>0
  26012.             return (1)
  26013.         exec @retcode = dbo.sp_MS_marksystemobject  @sel_procname 
  26014.         if @@ERROR<>0 OR @retcode <>0 return (1)
  26015.         select @command = 'grant exec on ' + quotename(@sel_procname) + ' to public'
  26016.         exec (@command)
  26017.         if @@ERROR<>0 return (1)
  26018.         end
  26019.         
  26020. go
  26021. exec dbo.sp_MS_marksystemobject sp_MSmakearticleprocs
  26022. go
  26023. grant exec on dbo.sp_MSmakearticleprocs to public
  26024. go
  26025.  
  26026. raiserror('Creating procedure sp_MSupdatesysmergearticles', 0,1)
  26027. GO
  26028.  
  26029. CREATE PROCEDURE sp_MSupdatesysmergearticles(
  26030.     @object                    sysname,                 /* Name of the table */
  26031.     @artid                    uniqueidentifier,        /* Article ID */
  26032.     @owner                    sysname             = NULL,
  26033.     @identity_support        int                    = NULL,
  26034.     @next_seed                bigint                = NULL,
  26035.     @range                    bigint                = NULL,
  26036.     @threshold                int                    = NULL,
  26037.     @pubid                    uniqueidentifier     = NULL
  26038.     ) AS
  26039.     declare @merge_pub_object_bit     int
  26040.     declare @id                        int
  26041.     declare @qualified_name            nvarchar(270)
  26042.     declare @colid                    int
  26043.     declare @colname                sysname
  26044.     declare @mergepublish            int
  26045.     SET NOCOUNT ON
  26046.     
  26047.     declare @retcode int
  26048.     declare @objid int
  26049.  
  26050.     /*
  26051.     ** Check to see if current publication has permission
  26052.     */
  26053.     /*
  26054.     ** Check for subscribing permission
  26055.     */
  26056.     exec @retcode=sp_MSreplcheck_subscribe
  26057.     if @retcode<>0 or @@ERROR<>0 return (1)
  26058.  
  26059.     if @owner is NULL or @owner = ''
  26060.     begin
  26061.         if exists (select name from sysobjects where id = object_id(@object))
  26062.             select @owner = user_name(uid) from sysobjects where id = object_id(QUOTENAME(@object))
  26063.         else 
  26064.             begin
  26065.                 raiserror(21078, 16, -1, @object)
  26066.                 return (1)
  26067.             end
  26068.     end
  26069.  
  26070.     select @mergepublish = 0x4000
  26071.     
  26072.     select @qualified_name = QUOTENAME(@owner) + '.' + QUOTENAME(@object)
  26073.     select @objid = object_id(@qualified_name)
  26074.     
  26075.     select @merge_pub_object_bit     = 128
  26076.  
  26077.     if (@artid is NULL)
  26078.     BEGIN
  26079.         RAISERROR (14057, 16, -1)
  26080.         RETURN (1)
  26081.     END
  26082.     begin tran
  26083.     save tran sp_MSupdatesysmergearticles
  26084.         if exists (select name from sysobjects where id = @objid)
  26085.         begin
  26086.             exec dbo.sp_replupdateschema @qualified_name
  26087.             if @@ERROR<>0 goto UNDO
  26088.             update sysobjects set replinfo = replinfo | @merge_pub_object_bit where id=@objid
  26089.             if @@ERROR<>0 goto UNDO
  26090.             update syscolumns set colstat=colstat | @mergepublish where id=@objid
  26091.             if @@ERROR<>0 goto UNDO
  26092.         /*
  26093.         ** update sysmergearticles.objid for all articles sharing the same base table
  26094.         */
  26095.         update sysmergearticles set objid = @objid where artid = @artid
  26096.             IF @@ERROR <> 0
  26097.             BEGIN
  26098.             RAISERROR (14057, 16, -1)
  26099.             goto UNDO
  26100.         END
  26101.         /*
  26102.         ** update sysmergearticles.sysnc_objid for only the article in this publication
  26103.         ** and for articles that no longer has a valid sync_objid (usually for the
  26104.         ** non-filtered case)
  26105.         */
  26106.         update sysmergearticles set sync_objid=@objid 
  26107.          where artid = @artid 
  26108.            and (pubid = @pubid or 
  26109.                 (object_name(sync_objid) is null and isnull(view_type,0) = 0))
  26110.         IF @@ERROR <> 0
  26111.         BEGIN
  26112.             RAISERROR (14057, 16, -1)
  26113.             goto UNDO
  26114.         END
  26115.             
  26116.             
  26117.         /*
  26118.         ** Set the next_seed, max value, and threshhold of identity table. New range and threshold are to be set
  26119.         ** by sp_addmergearticle if the table is to be republished. Message based subscribers have to look up the
  26120.         ** threshold and range info to see if they need to request a new range. Use max_identity for current_max for
  26121.         ** now. The value of current_max can change by sp_addmergearticle if republished.
  26122.         */
  26123.         if @identity_support = 1
  26124.         begin
  26125.             exec @retcode = sp_MSreseed @objid, @next_seed, @range
  26126.             if @@ERROR<>0 or @retcode<>0
  26127.                 GOTO UNDO
  26128.             insert MSrepl_identity_range (objid, max_identity, next_seed, current_max, range, threshold) 
  26129.                 values(@objid, @next_seed + @range, @next_seed, @next_seed + @range - 1, @range, @threshold)
  26130.             if @@ERROR<>0
  26131.             begin
  26132.                 GOTO UNDO
  26133.             end
  26134.         end
  26135.         
  26136.         end
  26137.         else -- THIS IS FINE. This dynamic query is there to provide a good error message. No need to use SP.
  26138.             raiserror(21078, 16, -1, @object)
  26139.             exec dbo.sp_replupdateschema @qualified_name
  26140.             if @@error<>0 goto UNDO
  26141.     commit tran
  26142.     RETURN 0
  26143. UNDO:
  26144.     rollback tran sp_MSupdatesysmergearticles
  26145.     commit tran
  26146.     RETURN 1
  26147. go
  26148. exec dbo.sp_MS_marksystemobject sp_MSupdatesysmergearticles
  26149. go
  26150. grant exec on dbo.sp_MSupdatesysmergearticles to public
  26151. go
  26152.  
  26153.  
  26154. raiserror('Creating procedure sp_MSexclause', 0,1)
  26155. GO
  26156.  
  26157. create proc sp_MSexclause  @tablenick int, @pubid uniqueidentifier  as
  26158. set nocount on
  26159. declare @clause nvarchar(4000)
  26160. declare @filterid int
  26161. declare @joinnick int
  26162. declare @jointable nvarchar(270)
  26163. declare @table nvarchar(270)
  26164. declare @basetable nvarchar(270)
  26165. declare @filter_clause nvarchar(2000)
  26166. declare @retcode int
  26167.  
  26168. exec @retcode= sp_MStablenamefromnick @tablenick, @basetable out
  26169. if @@error<>0 or @retcode<>0 return(1)
  26170. select @table = QUOTENAME(name)  from sysobjects where id in (select 
  26171.             objid from sysmergearticles where nickname = @tablenick)
  26172.  
  26173. declare f_c CURSOR LOCAL FAST_FORWARD for  select art_nickname, join_filterclause 
  26174.     from sysmergesubsetfilters where join_nickname = @tablenick and pubid = @pubid
  26175.     FOR READ ONLY
  26176. open f_c
  26177. fetch next from f_c into @joinnick, @filter_clause
  26178. while (@@fetch_status <> -1)
  26179.     begin
  26180.     exec @retcode= sp_MStablenamefromnick @joinnick, @jointable out
  26181.     if @@error<>0 or @retcode<>0 goto Failure
  26182.     -- As helper proc for sp_MSmakeinsertproc, we can insert directly to the
  26183.     -- temp table as we build up more commands for the insert proc.
  26184.     -- Our commands are part of phase 8...
  26185.     set @clause = ' 
  26186.         if @has_rows = 0 
  26187.         begin
  26188.             if exists (select 1 from ' + @basetable + ' (NOLOCK) , ' + @jointable + ' (NOLOCK) where '
  26189.  
  26190.     insert into #tempcmd (phase, cmdtext) values (8, @clause)
  26191.  
  26192.     set @clause = @filter_clause
  26193.     
  26194.     insert into #tempcmd (phase, cmdtext) values (8, @clause)
  26195.  
  26196.     set @clause = 
  26197.             ' and ' + @table + '.rowguidcol = @rowguid)    
  26198.                 select @has_rows = 1
  26199.         end
  26200. '
  26201.     insert into #tempcmd (phase, cmdtext) values (8, @clause)
  26202.  
  26203.     fetch next from f_c into @joinnick, @filter_clause
  26204.     end
  26205.  
  26206. close f_c
  26207. deallocate f_c
  26208.  
  26209. return(0)
  26210.  
  26211. Failure:
  26212.     close f_c
  26213.     deallocate f_c
  26214.     return(1)
  26215. go
  26216.  
  26217. exec dbo.sp_MS_marksystemobject sp_MSexclause  
  26218. go
  26219. raiserror('Creating procedure sp_MSgetcolordinalfromcolname', 0,1)
  26220. GO
  26221.  
  26222.  
  26223. -- @colname should not be quoted when the following procedure is called
  26224. create proc sp_MSgetcolordinalfromcolname @objid int, @sync_objid int, @colname sysname, @colordinal int OUTPUT  as
  26225.  
  26226.     declare @colid         int
  26227.     declare @objcolname sysname
  26228.     declare @iscomputed    tinyint
  26229.     declare @xtype        tinyint
  26230.  
  26231.     select @colid = min (colid) from syscolumns where id = @sync_objid and 
  26232.         name not in (select name from syscolumns where id=@objid and (iscomputed=1 OR type_name(xtype)='timestamp'))
  26233.         
  26234.     select @objcolname = name from syscolumns where id = @sync_objid and colid = @colid
  26235.     select @iscomputed=iscomputed, @xtype = xtype from syscolumns where id = @objid and name = @colname
  26236.     set @colordinal = 1
  26237.  
  26238.     while (@objcolname is not null and @objcolname <> @colname)
  26239.     begin
  26240.         if (@iscomputed=1 OR type_name(@xtype)='timestamp')
  26241.             goto Next_Column
  26242.  
  26243.     Next_Column:
  26244.         -- now set up to repeat the loop with the next column
  26245.         select @colid = min (colid) from syscolumns where id = @sync_objid and colid > @colid 
  26246.         
  26247.         set @objcolname = NULL
  26248.         if @colid is not null
  26249.             begin
  26250.                 select @objcolname = name from syscolumns where id = @sync_objid and colid = @colid
  26251.                 select @iscomputed=iscomputed, @xtype = xtype from syscolumns where id = @objid and name = @colname
  26252.             end
  26253.  
  26254.         set @colordinal = @colordinal + 1
  26255.     end
  26256.  
  26257.     return 0 
  26258. go
  26259.  
  26260. exec dbo.sp_MS_marksystemobject sp_MSgetcolordinalfromcolname  
  26261. go
  26262.  
  26263. raiserror('Creating procedure sp_MSinsertbeforeimageclause', 0,1)
  26264. GO
  26265.  
  26266. create proc sp_MSinsertbeforeimageclause @pubid uniqueidentifier, @objid int, @tablenickstr nvarchar(12)  as
  26267.     set nocount on
  26268.     declare @cmdpiece nvarchar(4000)
  26269.     declare @before_objid int
  26270.     declare @sync_objid int
  26271.     declare @before_name sysname
  26272.     declare @collist nvarchar(4000)
  26273.     declare @vallist nvarchar(4000)
  26274.     declare @colname sysname
  26275.     declare @colordinal smallint
  26276.     declare @argname sysname
  26277.  
  26278.     -- Do we have a before table?
  26279.     select @before_objid = max(before_image_objid) from  sysmergearticles where objid = @objid and
  26280.             before_image_objid is not null
  26281.     select @before_name = OBJECT_NAME(@before_objid)
  26282.  
  26283.     select @sync_objid = sync_objid    from sysmergearticles where objid=@objid and pubid=@pubid
  26284.  
  26285.     if @before_name is null
  26286.         begin
  26287.             return 0
  26288.         end
  26289.  
  26290.     set @collist = ''
  26291.     -- Loop over columns to make the column list for the insert / select command
  26292.     declare col_cursor CURSOR LOCAL FAST_FORWARD for select name from syscolumns
  26293.     where id = @before_objid and name <> 'generation' and name <> 'system_delete' order by colid
  26294.     FOR READ ONLY
  26295.  
  26296.     open col_cursor
  26297.     set @vallist = ''
  26298.     fetch next from col_cursor into @colname
  26299.     while (@@fetch_status <> -1)
  26300.         begin
  26301.         --this column is not in vertical partitioning
  26302.         if not exists (select * from syscolumns where name=@colname and id=@sync_objid)
  26303.         begin
  26304.             fetch next from col_cursor into @colname
  26305.             continue
  26306.         end
  26307.         
  26308.         set @collist = @collist + QUOTENAME(@colname) + ', '
  26309.         exec sp_MSgetcolordinalfromcolname @objid, @sync_objid, @colname, @colordinal out
  26310.         select @argname = '@p' + rtrim(convert(nchar, @colordinal))
  26311.         set @vallist = @vallist + @argname + ', '
  26312.         fetch next from col_cursor into @colname
  26313.         end
  26314.     close col_cursor
  26315.     deallocate col_cursor
  26316.  
  26317.     -- Our list has all of the columns except generation since that gets set to a local variable
  26318.     -- Make the insert command
  26319.     set @cmdpiece = ' declare @gen_cur int select @gen_cur = max(gen_cur) from sysmergearticles where nickname = ' + @tablenickstr
  26320.     insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)
  26321.     --select @cmdpiece
  26322.  
  26323.     set @cmdpiece = ' insert into ' + QUOTENAME(@before_name) + ' ( ' + @collist +    
  26324.                     ' generation, system_delete) values (' + @vallist + ' @gen_cur, 1 )'
  26325.     insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)
  26326.     --select @cmdpiece
  26327.  
  26328.     return 0
  26329.     
  26330. go
  26331.  
  26332. exec dbo.sp_MS_marksystemobject sp_MSinsertbeforeimageclause  
  26333. go
  26334.  
  26335.  
  26336. raiserror('Creating procedure sp_MScreatedupkeyupdatequery', 0,1)
  26337. GO
  26338. create procedure sp_MScreatedupkeyupdatequery
  26339.     @tablename nvarchar(270),
  26340.     @tablenickstr nvarchar(12),
  26341.     @phase int,
  26342.     @isconflictproc bit
  26343. as
  26344.     declare @uniqueindexid        smallint
  26345.     declare @numofindex            smallint
  26346.     declare @cmdpiece            nvarchar(4000)
  26347.     declare @cmdpiecebegin        nvarchar(1000)
  26348.     declare @colid                int
  26349.     declare @tableid            int
  26350.     declare @colname            nvarchar(140)
  26351.     declare @paramname            nvarchar(10)
  26352.     declare @skipthisindex        bit
  26353.  
  26354.     set @numofindex= 0
  26355.     set @cmdpiece= ''
  26356.     set @cmdpiecebegin= ''
  26357.     set @tableid= object_id(@tablename)
  26358.  
  26359.     if 1 = @isconflictproc
  26360.     begin
  26361.         -- Find the the column that contains the reason_code.
  26362.         set @colname= '[reason_code]' 
  26363.         select @paramname= paramname from #coltab where colname=@colname
  26364.  
  26365.         set @cmdpiecebegin= '
  26366.         declare @error    int
  26367.         set @error= ' + @paramname + '
  26368.         '
  26369.     end
  26370.     
  26371.     -- Create the part of the query that preceds the where-clause.
  26372.     set @cmdpiecebegin= @cmdpiecebegin + '
  26373.  
  26374.     declare @REPOLEExtErrorDupKey            int
  26375.     declare @REPOLEExtErrorDupUniqueIndex    int
  26376.  
  26377.     set @REPOLEExtErrorDupKey= 2627
  26378.     set @REPOLEExtErrorDupUniqueIndex= 2601
  26379.     
  26380.     if @error in (@REPOLEExtErrorDupUniqueIndex, @REPOLEExtErrorDupKey)
  26381.     begin
  26382.         update mc
  26383.             set mc.generation= 0
  26384.             from dbo.MSmerge_contents mc join ' + @tablename + ' t on mc.rowguid=t.rowguidcol
  26385.             where
  26386.                 mc.tablenick = ' + @tablenickstr + ' and
  26387.                 (
  26388. '
  26389.     -- Iterate over all unique indexes, and build up the column comparison part of the where-clause.
  26390.     -- The index on rowguidcol is skipped.
  26391.     -- Exit right away if there is no index at all, or only the merge-related rowguidcol-index.
  26392.     set @uniqueindexid= (select min(indid) from dbo.sysindexes 
  26393.                             where id=@tableid and 
  26394.                                   1=IndexProperty(id, name, 'IsUnique') and
  26395.                                   (
  26396.                                       1<>ColumnProperty(id, index_col(@tablename, indid, 1), 'IsRowGuidCol') or
  26397.                                       index_col(@tablename, indid, 2) is not null
  26398.                                   )
  26399.                         )
  26400.  
  26401.     while @uniqueindexid is not null
  26402.     begin
  26403.         set @skipthisindex= 0
  26404.         set @colid= 1
  26405.  
  26406.         set @numofindex= @numofindex + 1
  26407.         
  26408.         -- Iterate over all columns that belong to that index.
  26409.         set @cmdpiece= ''
  26410.         set @colname= index_col(@tablename, @uniqueindexid, @colid)
  26411.         while 0 = @skipthisindex and 
  26412.               @colname is not null
  26413.         begin
  26414.             set @colname= quotename(@colname)
  26415.             set @paramname= (select paramname from #coltab where colname = @colname)
  26416.  
  26417.             -- @paramname can be null if we are in the update proc, and the column is
  26418.             -- an identity column. (Those columns are skipped for the update proc, and thus
  26419.             -- are not in #coltab, either.)
  26420.             -- As a consequence, this part of the where clause is skipped, too. 
  26421.             if @paramname is null
  26422.             begin
  26423.                 set @skipthisindex= 1
  26424.                 set @numofindex= @numofindex - 1
  26425.             end
  26426.             else
  26427.             begin
  26428.  
  26429.                 if 1 = @colid
  26430.                 begin
  26431.                     if 1 < @numofindex
  26432.                         set @cmdpiece= @cmdpiece + '                        or
  26433. '
  26434.  
  26435.                     set @cmdpiece= @cmdpiece + '                        (t.' + @colname + '=' + @paramname
  26436.                 end
  26437.                 else
  26438.                 begin
  26439.                     set @cmdpiece= @cmdpiece + ' and t.' + @colname + '=' + @paramname
  26440.                 end
  26441.                 
  26442.                 set @colid= @colid+1
  26443.                 set @colname= index_col(@tablename, @uniqueindexid, @colid)
  26444.             end
  26445.             
  26446.         end
  26447.  
  26448.         if 0 = @skipthisindex
  26449.         begin
  26450.             -- Add the beginning of the command if we are at the first index
  26451.             if 1 = @numofindex
  26452.                 insert into #tempcmd (phase, cmdtext) values (@phase, @cmdpiecebegin)
  26453.             -- Close this part of the where-clause, and add it to the generated query.
  26454.             set @cmdpiece= @cmdpiece + ')'
  26455.             insert into #tempcmd (phase, cmdtext) values (@phase, @cmdpiece)
  26456.         end
  26457.  
  26458.         set @uniqueindexid= (select min(indid) from dbo.sysindexes 
  26459.                                 where id=@tableid and 
  26460.                                     1=IndexProperty(id, name, 'IsUnique') and
  26461.                                       (
  26462.                                           1<>ColumnProperty(id, index_col(@tablename, indid, 1), 'IsRowGuidCol') or
  26463.                                           index_col(@tablename, indid, 2) is not null
  26464.                                       ) and
  26465.                                     indid>@uniqueindexid
  26466.                             )
  26467.     end
  26468.  
  26469.     -- Close the entire where-clause.
  26470.     if 0 < @numofindex
  26471.     begin
  26472.         set @cmdpiece= '
  26473.                         )
  26474.             end'
  26475.         
  26476.         insert into #tempcmd (phase, cmdtext) values (@phase, @cmdpiece)
  26477.     end
  26478. go
  26479. exec dbo.sp_MS_marksystemobject sp_MScreatedupkeyupdatequery 
  26480. go
  26481.  
  26482.  
  26483. raiserror('Creating procedure sp_MSmakeinsertproc', 0,1)
  26484. GO
  26485.  
  26486. -- This will be called by snapshot at publisher side and 
  26487. -- merge at the subscriber side, check for dbo permission
  26488. create procedure sp_MSmakeinsertproc 
  26489.     (@tablename sysname, @ownername sysname, @procname sysname, @pubid uniqueidentifier)
  26490. as
  26491. declare @argname            sysname
  26492. declare @id                 int
  26493. declare @sync_objid            int
  26494. declare @qualified_name        nvarchar(270)
  26495. declare @idstr                nvarchar(100)
  26496. declare @iscomputed            tinyint
  26497. declare @xtype                tinyint
  26498. declare @colstat             int
  26499. declare @permissions        int
  26500. declare @permissions_str     nvarchar(10)
  26501.  
  26502. if @ownername is NULL or @ownername=''
  26503.     select @qualified_name = QUOTENAME(@tablename)
  26504. else    
  26505.     select @qualified_name = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename)
  26506.     
  26507. select @id = object_id(@qualified_name)
  26508. if @id is NULL return (1)
  26509.  
  26510. select @sync_objid = sync_objid, @permissions_str=convert(nvarchar(10),check_permissions), @permissions=check_permissions
  26511.     from sysmergearticles where objid=@id and pubid=@pubid
  26512.  
  26513. set @idstr = rtrim(convert(nchar, @id))    
  26514.  
  26515. declare @retcode int
  26516. declare @colname nvarchar(140)
  26517. declare @rgcolname nvarchar(140)
  26518. declare @typename nvarchar(140)
  26519. declare @colid smallint
  26520. declare @status tinyint
  26521. declare @len smallint
  26522. declare @prec int
  26523. declare @scale int
  26524. declare @tablenick int
  26525. declare @tablenickstr nvarchar(12)
  26526. declare @colordinal smallint
  26527. declare @cmdpiece nvarchar(4000)
  26528.  
  26529. set nocount on
  26530.  
  26531. -- Check for subscribing permission
  26532. exec @retcode=sp_MSreplcheck_subscribe
  26533. if @retcode<>0 or @@ERROR<>0 return (0)
  26534.     
  26535. execute @retcode = dbo.sp_MStablenickname @ownername, @tablename, @tablenick output
  26536. IF @@ERROR <> 0 or @retcode <>0 return (0)
  26537. set @tablenickstr = rtrim(convert(nchar, @tablenick))
  26538.  
  26539. -- create temp table to select the command text out of
  26540. create table #tempcmd (phase int NOT NULL, step int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)
  26541.  
  26542. create table #coltab (colname nvarchar(140), paramname nvarchar(10))
  26543.  
  26544. -- insert text pieces that don't repeat for each column
  26545.  
  26546. -- phase 0 : create procedure and fixed part of argument list
  26547. set @cmdpiece = 'create procedure dbo.'  + QUOTENAME(@procname) + ' (@rowguid uniqueidentifier, 
  26548.     @generation int, @lineage varbinary(255),  @colv varbinary(2048) '
  26549. insert into #tempcmd (phase, cmdtext) values (0, @cmdpiece)
  26550.  
  26551. -- phase 1 is rest of argument list; goes in during loop over columns
  26552. -- phase 2 : paren to close argument list, and variable declarations
  26553. set @cmdpiece = ') as
  26554.     declare @tablenick int
  26555.     declare @errcode int
  26556.     declare @retcode int
  26557.     declare @has_rows int
  26558.     declare @rowcount int
  26559.     declare @error int
  26560.  
  26561.     set @has_rows = 0
  26562.     set @errcode= 0
  26563.  
  26564.     set nocount on
  26565.  
  26566.  
  26567.     -- role based security check
  26568.     if ({ fn ISPALUSER(''' + convert(nvarchar(36),@pubid) + ''') } <> 1)
  26569.     begin
  26570.         RAISERROR (14126, 11, -1)
  26571.         return (3)
  26572.     end
  26573.     '
  26574.     if @permissions>0
  26575.         begin
  26576.             select @cmdpiece = @cmdpiece + ' exec @retcode = dbo.sp_MSreplcheck_permission @objid = ' + @idstr + ', @type = 1, @permissions = ' + @permissions_str + '
  26577.                 if @retcode<>0 or @@ERROR<>0 return (4)'
  26578.         end    
  26579.     select @cmdpiece = @cmdpiece + '
  26580.     select @tablenick = ' + @tablenickstr
  26581.  
  26582. insert into #tempcmd (phase, cmdtext) values (2, @cmdpiece)
  26583.  
  26584. -- phase 3 is optional set identity insert on, goes in during loop if needed
  26585. -- phase 4 is beginning a sub transaction, setting save point and starting insert statement
  26586. set @cmdpiece = '
  26587.     begin transaction
  26588.     save transaction sp_insproc
  26589.     if @metadata_type = 1 or @metadata_type = 5
  26590.     begin
  26591.         if not exists (select * from dbo.MSmerge_tombstone where tablenick = @tablenick and rowguid = @rowguid and
  26592.                         lineage = @lineage_old)
  26593.         begin
  26594.             set @errcode= 2
  26595.  
  26596.             goto Failure
  26597.         end
  26598.     end
  26599.     exec @retcode= dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage, @colv, 2, ''' + convert(nvarchar(36),@pubid) + ''', @tombstone_rows_deleted = @has_rows OUTPUT
  26600.     if @retcode<>0 or @@ERROR<>0
  26601.     begin
  26602.         set @errcode= 0
  26603.         goto Failure
  26604.     end
  26605.     insert into ' + @qualified_name + ' ('
  26606. insert into #tempcmd (phase, cmdtext) values (4, @cmdpiece)
  26607.  
  26608. -- phase 5 is column list that we are inserting; done in loop
  26609.  
  26610. -- phase 6 is just the opening and closing parens and VALUES keyword
  26611. set @cmdpiece = ') values ('
  26612. insert into #tempcmd (phase, cmdtext) values (6, @cmdpiece)
  26613.  
  26614. -- phase 7 is all of those arguments as the list of value expressions; done in loop
  26615. -- phase 8 finish insert, check status, etc.
  26616. -- if we have a permanent view, check for case where we inserted a row that doesn't
  26617. -- meet filters of subscriber we are getting the insert from
  26618. set @cmdpiece = ')
  26619.     select @rowcount= @@rowcount, @error= @@error
  26620.     if (@rowcount <> 1)
  26621.     begin
  26622.         set @errcode= 3
  26623.         goto Failure
  26624.     end
  26625. '
  26626. insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)
  26627.  
  26628. -- only add the following code when creating proc at publisher
  26629. if exists (select 1 from sysmergepublications where  pubid=@pubid and LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name())
  26630. begin
  26631.     -- Add in pieces that check for inserting a row that instantly means other rows need to be downloaded
  26632.     -- If we insert such a row, set the generation and partchangegen so that we will download everything
  26633.     -- that needs to go.
  26634.  
  26635.     exec sp_MSexclause @tablenick, @pubid
  26636.     if @@error<>0 return(1)
  26637.  
  26638.     if exists (select * from sysmergearticles where pubid = @pubid and objid = @id and view_type = 1)
  26639.     begin
  26640.         /* Get name of rowguidcol. Aliasing doesn't work through a view. */
  26641.         select @rgcolname = QUOTENAME(name) from syscolumns where id = @id and ColumnProperty(@id, name, 'isrowguidcol') = 1
  26642.         if @rgcolname is null
  26643.             set @rgcolname = 'rowguid'
  26644.         select @cmdpiece = ' 
  26645.             if @has_rows = 0
  26646.                 begin
  26647.                     if not exists (select 1 from ' + QUOTENAME(OBJECT_NAME(sync_objid))
  26648.             from sysmergearticles where pubid = @pubid and objid = @id
  26649.         set @cmdpiece = @cmdpiece + ' where ' + @rgcolname + ' = @rowguid) 
  26650.                     begin
  26651.                         select @has_rows = 1 '
  26652.         insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)
  26653.  
  26654.         exec sp_MSinsertbeforeimageclause @pubid, @id, @tablenickstr
  26655.  
  26656.         set @cmdpiece = ' 
  26657.                     end    
  26658.                 end '
  26659.         insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)
  26660.     end
  26661. end
  26662. -- if we already have a tombstone for this row, (especially a remove from partial) then
  26663. -- make sure we will set the generation so that it goes on down to subscribers of republishers
  26664. -- for backward compatibility, for 7.0 subscribers we do not want @has_rows to be 1
  26665.  
  26666. set @cmdpiece = '
  26667.             if @has_rows > 0     
  26668.                 update dbo.MSmerge_contents set generation = 0, partchangegen = 0 
  26669.                     where rowguid = @rowguid and tablenick = @tablenick'
  26670. insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)
  26671.  
  26672. set @cmdpiece = '
  26673.  
  26674.     commit tran
  26675. '
  26676. insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)
  26677.  
  26678. -- phase 9 is setting identity insert off if needed; done in loop
  26679.  
  26680. -- now loop over columns and insert missing command pieces
  26681.  
  26682. select @colid = min (colid) from syscolumns where id = @sync_objid and 
  26683.     name not in (select name from syscolumns where id=@id and (iscomputed=1 OR type_name(xtype)='timestamp'))
  26684.     
  26685. select @colname = QUOTENAME(name), @typename = type_name(xtype),
  26686.     @len = length,     @prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale
  26687.     from syscolumns 
  26688.     where id = @sync_objid and colid = @colid
  26689. select @status = status, @iscomputed=iscomputed, @xtype=xtype, @colstat=colstat from syscolumns 
  26690.     where id = @id and QUOTENAME(name) = @colname
  26691. if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
  26692.     select @len = @len/2
  26693. set @colordinal = 1
  26694.  
  26695. while (@colname is not null)
  26696.     begin
  26697.     if (@iscomputed=1 OR type_name(@xtype)='timestamp')
  26698.         goto Next_Column
  26699.     exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale
  26700.     if @@error<>0 OR @retcode <>0 return (1)
  26701.  
  26702.     select @argname = '@p' + rtrim(convert(nchar, @colordinal))
  26703.  
  26704.     insert into #coltab (colname, paramname) values (@colname, @argname)
  26705.     
  26706.     -- add to argument list (phase 1)
  26707.     set @cmdpiece = ', ' + @argname + ' ' + @typename
  26708.     insert into #tempcmd (phase, cmdtext) values (1, @cmdpiece)
  26709.  
  26710.     -- add to column list and value list
  26711.     if (@colordinal = 1)
  26712.         begin
  26713.         -- column list is phase 5
  26714.         set @cmdpiece = @colname
  26715.         insert into #tempcmd (phase, cmdtext) values (5, @cmdpiece)
  26716.  
  26717.         -- argname for values list is phase 7
  26718.         set @cmdpiece = @argname
  26719.         insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece)
  26720.         end
  26721.     else
  26722.         begin
  26723.         -- column list is phase 5; need preceding comma since not the first one.
  26724.         set @cmdpiece = ', ' + @colname
  26725.         insert into #tempcmd (phase, cmdtext) values (5, @cmdpiece)
  26726.  
  26727.         -- argname for values list is phase 7 need preceding comma since not the first one.
  26728.         set @cmdpiece = ', ' + @argname
  26729.         insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece)
  26730.         end
  26731.         
  26732.     -- is this an identity column without 'not for replication' marking?
  26733.     if (@status = 128) and (@colstat & 0x0008 =0)
  26734.         begin
  26735.         -- turning identity insert on is phase 3
  26736.         set @cmdpiece = '
  26737.     set identity_insert ' + @qualified_name + ' on'
  26738.         insert into #tempcmd (phase, cmdtext) values (3, @cmdpiece)
  26739.  
  26740.         -- turning identity insert on is phase 9
  26741.         set @cmdpiece = '
  26742.     set identity_insert ' + @qualified_name + ' off'
  26743.         insert into #tempcmd (phase, cmdtext) values (9, @cmdpiece)
  26744.         end
  26745.  
  26746. Next_Column:
  26747.     -- now set up to repeat the loop with the next column
  26748.     select @colid = min (colid) from syscolumns where id = @sync_objid and colid > @colid 
  26749.         
  26750.     set @colname = NULL
  26751.     if @colid is not null
  26752.         select @colname = QUOTENAME(name), @status = status, @typename = type_name(xtype), @len = length,
  26753.         @prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale
  26754.         from syscolumns where id = @sync_objid and colid = @colid
  26755.     select @status = status, @iscomputed=iscomputed, @xtype=xtype,@colstat=colstat from syscolumns 
  26756.         where id = @id and QUOTENAME(name) = @colname
  26757.         
  26758.     if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
  26759.         select @len = @len/2
  26760.     set @colordinal = @colordinal + 1
  26761.     end
  26762.  
  26763.     select @cmdpiece = ',@metadata_type tinyint = NULL, @lineage_old varbinary(255) = NULL'
  26764.     insert into #tempcmd (phase, cmdtext) values (1, @cmdpiece)
  26765.     
  26766. -- Now we select out the command text pieces in proper order so that our caller,
  26767. -- xp_execresultset will execute the command that creates the stored procedure.
  26768.  
  26769. -- phase 10 is returning our success / failure status
  26770. set @cmdpiece = '
  26771.  
  26772.     return(1)
  26773.     
  26774. Failure:
  26775.     rollback tran sp_insproc
  26776.     commit tran    
  26777.  
  26778.     '
  26779. insert into #tempcmd (phase, cmdtext) values (10, @cmdpiece)
  26780.  
  26781. exec dbo.sp_MScreatedupkeyupdatequery
  26782.             @tablename= @qualified_name,
  26783.             @tablenickstr= @tablenickstr,
  26784.             @phase= 10,
  26785.             @isconflictproc= 0
  26786.  
  26787. set @cmdpiece= '
  26788.     return(@errcode)
  26789.     '
  26790. insert into #tempcmd (phase, cmdtext) values (10, @cmdpiece)
  26791.  
  26792. select cmdtext from #tempcmd order by phase, step
  26793. drop table #tempcmd
  26794. drop table #coltab
  26795. go
  26796.  
  26797. exec dbo.sp_MS_marksystemobject sp_MSmakeinsertproc 
  26798. go
  26799. grant exec on dbo.sp_MSmakeinsertproc to public
  26800. go
  26801.  
  26802. raiserror('Creating procedure sp_MSmakeupdateproc', 0,1)
  26803. GO
  26804.  
  26805. -- This will be called by snapshot at publisher side and 
  26806. -- merge at the subscriber side, check for dbo permission
  26807. create procedure sp_MSmakeupdateproc 
  26808.     (@tablename sysname, @ownername sysname, @procname sysname, @pubid uniqueidentifier)
  26809. as
  26810. declare @retcode             int
  26811. declare @argname            nvarchar(10)
  26812. declare @varname            nvarchar(10)
  26813. declare @cmdpiece            nvarchar(4000)
  26814. declare @qualified_name        nvarchar(270)
  26815. declare @littlecomp            nvarchar(300)
  26816. declare @id                    int
  26817. declare @sync_objid            int
  26818. declare @idstr                nvarchar(100) 
  26819. declare @fast_multicol_updateproc_bit bit
  26820. declare @permissions_str    nvarchar(10)
  26821. declare @permissions        int
  26822.  
  26823. set nocount on
  26824.  
  26825. if @ownername is NULL or @ownername=''
  26826.     select @qualified_name = QUOTENAME(@tablename)
  26827. else    
  26828.     select @qualified_name = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename)
  26829.  
  26830. select @id = object_id(@qualified_name)
  26831.     if @id is NULL return (1)
  26832.  
  26833. select @sync_objid = sync_objid, @fast_multicol_updateproc_bit = fast_multicol_updateproc, @permissions=check_permissions,
  26834.         @permissions_str=convert(nvarchar(10), check_permissions) from sysmergearticles 
  26835.         where objid=@id and pubid = @pubid
  26836.     
  26837. set @idstr = rtrim(convert(nchar, @id))    
  26838.  
  26839. declare @colname nvarchar(140)
  26840. declare @typename nvarchar(140)
  26841. declare @colid smallint
  26842. declare @colordinal smallint
  26843. declare @colordstr nvarchar(4)
  26844. declare @xtype        tinyint
  26845. declare @iscomputed tinyint
  26846. declare @isrowguidcol tinyint
  26847. declare @separate_update_needed tinyint
  26848. declare @update_stmt_started tinyint
  26849. declare @status tinyint
  26850. declare @len smallint
  26851. declare @blen smallint
  26852. declare @prec int
  26853. declare @scale int
  26854. declare @tablenick int
  26855. declare @tablenickstr nvarchar(12)
  26856. declare @bytestr      nvarchar(10)
  26857. declare @byteordinal  smallint
  26858. declare @numbytes      smallint
  26859. declare @bitstr       nvarchar(10)
  26860. declare @colpat          nvarchar(130)
  26861. declare @has_updateable_columns_in_select_list bit
  26862. select @separate_update_needed = 0
  26863. select @update_stmt_started = 0
  26864. select @has_updateable_columns_in_select_list = 0
  26865.     /*
  26866.     ** Check for dbo permission
  26867.     */
  26868.     exec @retcode=sp_MSreplcheck_subscribe
  26869.     if @retcode<>0 or @@ERROR<>0 return (1)
  26870.     
  26871. execute @retcode = dbo.sp_MStablenickname @ownername, @tablename, @tablenick output
  26872. if @@ERROR <>0 OR @retcode <>0 return (1)
  26873. set @tablenickstr = rtrim(convert(nchar, @tablenick))
  26874.  
  26875. -- create temp table to select the command text out of
  26876. create table #tempcmd (phase int NOT NULL, step int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)
  26877.  
  26878. create table #coltab (colname nvarchar(140), paramname nvarchar(10))
  26879.  
  26880. -- insert text pieces that don't repeat for each column
  26881.  
  26882. -- phase 0 : create procedure and fixed part of argument list
  26883. set @cmdpiece = 'Create procedure dbo.' + quotename(@procname) + ' (@rowguid uniqueidentifier, @setbm varbinary(125) = NULL,
  26884.     @metadata_type tinyint, @lineage_old varbinary(255), @generation int,
  26885.     @lineage_new varbinary(255), @colv varbinary(2048) '
  26886. insert into #tempcmd (phase, cmdtext) values (0, @cmdpiece)
  26887.  
  26888. -- phase 1 is rest of argument list; goes in during loop over columns
  26889. -- phase 2 paren to close argument list and fixed variable declarations
  26890. set @cmdpiece = ') as
  26891.     declare @tablenick int
  26892.     declare @errcode int
  26893.     declare @fset int
  26894.     declare @match int
  26895.     declare @retcode smallint
  26896.     declare @rowcount int
  26897.     declare @error int
  26898.  
  26899.     set nocount on
  26900.  
  26901.     -- role based security check
  26902.     if ({ fn ISPALUSER(''' + convert(nvarchar(36),@pubid) + ''') } <> 1)
  26903.     begin
  26904.         RAISERROR (14126, 11, -1)
  26905.         return (3)
  26906.     end
  26907.     '
  26908.     if @permissions>0
  26909.         begin
  26910.         select @cmdpiece=@cmdpiece + '
  26911.             exec @retcode = dbo.sp_MSreplcheck_permission @objid = ' + @idstr + ', @type=2, @permissions = ' + @permissions_str + '
  26912.             if @retcode<>0 or @@ERROR<>0 return (4)'
  26913.         end
  26914.  
  26915.     select @cmdpiece = @cmdpiece + '
  26916.     select @tablenick = ' + @tablenickstr
  26917.  
  26918. insert into #tempcmd (phase, cmdtext) values (2, @cmdpiece)
  26919.  
  26920. -- phase 3 is rest of variable declarations; goes in during loop over columns
  26921. -- phase 4 begin a transaction, set savepoint in case we roll back, begin select to get current values
  26922. set @cmdpiece = '    begin transaction sub
  26923.     save transaction sub
  26924.     select '
  26925. insert into #tempcmd (phase, cmdtext) values (4, @cmdpiece)
  26926.  
  26927. -- phase 5 is middle part of select assigning column values to local variables -- goes in loop
  26928. -- phase 6 -- finish the select, check that metadata matches
  26929. set @cmdpiece = '    from ' + @qualified_name + ' (updlock) where rowguidcol = @rowguid
  26930.     exec @retcode= dbo.sp_MScheckmetadatamatch @metadata_type, @rowguid, @tablenick, @lineage_old, @match output
  26931.     if @retcode<>0 or @@ERROR<>0
  26932.     begin
  26933.         set @errcode= 3
  26934.         goto Failure
  26935.     end
  26936.     if (@match = 1)
  26937.     begin
  26938. '
  26939. insert into #tempcmd (phase, cmdtext) values (6, @cmdpiece)
  26940.  
  26941. -- phase 7 is a bunch of if's that compare old values with new values ; goes in during loop
  26942. -- phase 8 finish the stored procedure
  26943.  
  26944. -- now do the loop over all columns and insert the missing pieces
  26945.  
  26946. -- don't script out computed columns or timestamp columns
  26947. select @colid = min (colid) from syscolumns where id = @sync_objid and 
  26948.     name not in (select name from syscolumns where id=@id and (iscomputed=1 OR type_name(xtype)='timestamp'))
  26949. select @colname = NULL
  26950. select @colname = name, @typename = type_name(xtype), @blen = length,
  26951.     @prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale
  26952.     from syscolumns 
  26953.     where id = @sync_objid and colid = @colid
  26954. select @status = status, @iscomputed=iscomputed, @xtype=xtype,
  26955.     @isrowguidcol = COLUMNPROPERTY(id, name, 'IsRowGuidCol')
  26956.     from syscolumns 
  26957.     where id = @id and name = @colname
  26958.  
  26959. -- get col count to determine what size our bitmask is going to be
  26960. declare @colcount int
  26961. select @colcount = count(*) from syscolumns where id = @sync_objid and 
  26962.     name not in (select name from syscolumns where id=@id and (iscomputed=1 OR type_name(xtype)='timestamp'))    
  26963.  
  26964. set @cmdpiece = '        
  26965.     declare @colbitmask binary(' + convert(nvarchar,1+(@colcount-1) / 8) + ') 
  26966.     select @colbitmask = 0
  26967.     '
  26968.  
  26969. select @numbytes = 1+(@colcount-1) / 8
  26970. insert into #tempcmd (phase, cmdtext) values (2, @cmdpiece)
  26971.  
  26972. if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
  26973.     set @len = @blen/2
  26974. else
  26975.     set @len = @blen
  26976. set @colordinal = 1
  26977.  
  26978. declare @firstCol tinyint
  26979. set @firstCol= 1
  26980.  
  26981. while (@colname is not null)
  26982. begin
  26983.     
  26984.     set @colordstr = convert(nvarchar(4), @colordinal)
  26985.     exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale
  26986.     if @@ERROR <>0 OR @retcode <>0 return (1)
  26987.  
  26988.     if (@fast_multicol_updateproc_bit = 1)
  26989.     begin
  26990.         
  26991.         -- check if separate update statement is needed only if article supports fast multi-column updates.
  26992.  
  26993.         -- reset @separate_update_needed
  26994.         set @separate_update_needed = 0
  26995.     
  26996.         --check if this column is part of the filter or join filter clause.
  26997.         -- if so, use a separater update statement for it rather than setting bitmask for the one cumulative update statement.
  26998.         set @colpat = '%' + @colname + '%'
  26999.         -- does updating this column change membership in a partial replica? 
  27000.         if exists (select * from sysmergearticles where objid = @id and subset_filterclause like @colpat)
  27001.             set @separate_update_needed = 1
  27002.         else if exists (select * from sysmergesubsetfilters where art_nickname = @tablenick and join_filterclause like @colpat)
  27003.             set @separate_update_needed = 1
  27004.         else if exists (select * from sysmergesubsetfilters where join_nickname = @tablenick and join_filterclause like @colpat)
  27005.             set @separate_update_needed = 1
  27006.         else if (@typename = 'ntext' or @typename = 'text' or @typename = 'image')
  27007.             set @separate_update_needed = 1
  27008.     end
  27009.     else
  27010.     begin
  27011.         set @separate_update_needed = 1            -- separate update statement for each column.
  27012.     end
  27013.     
  27014.     if @status = 128 OR @iscomputed=1 OR type_name(@xtype)='timestamp'
  27015.         goto Next_Column
  27016.  
  27017.     set @colname = QUOTENAME(@colname)
  27018.  
  27019.     -- put in argument list element (phase 1)
  27020.     set @argname = '@p' + rtrim(@colordstr)
  27021.  
  27022.     insert into #coltab (colname, paramname) values (@colname, @argname)
  27023.  
  27024.     set @cmdpiece = ',
  27025.         ' + @argname + ' ' + @typename + ' = NULL '
  27026.  
  27027.     insert into #tempcmd (phase, cmdtext) values (1, @cmdpiece)
  27028.  
  27029.     if (@isrowguidcol = 1)
  27030.         goto Next_Column
  27031.  
  27032.     if (@separate_update_needed = 0)
  27033.     begin
  27034.         
  27035.         select @bytestr = convert( nvarchar, 1 + (@colordinal-1) / 8 )
  27036.         select @byteordinal = 1 + (@colordinal-1) / 8
  27037.         select @bitstr =  convert( nvarchar, power(2, (@colordinal-1) % 8 ) )
  27038.  
  27039.         if (@update_stmt_started = 0)
  27040.         begin
  27041.             select @update_stmt_started = 1
  27042.             select @cmdpiece = 'update ' + @qualified_name + ' set '
  27043.             insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)        -- goes after phase 7
  27044.             select @cmdpiece = ' where rowguidcol = @rowguid 
  27045.                 select @rowcount= @@rowcount, @error= @@error
  27046.                 if (@rowcount <> 1)
  27047.                 begin
  27048.                     set @errcode= 3
  27049.                     goto Failure
  27050.                 end'
  27051.             insert into #tempcmd (phase, cmdtext) values (10, @cmdpiece)    -- goes after phase 9 which would be the SET clause for different columns
  27052.         end
  27053.         else
  27054.         begin
  27055.             select @cmdpiece = ','
  27056.             insert into #tempcmd (phase, cmdtext) values (9, @cmdpiece)
  27057.         end
  27058.  
  27059.         select @cmdpiece = @colname + ' = case substring(@colbitmask,' + @bytestr + ',1) & ' + @bitstr + ' when ' + @bitstr + ' then ' + @argname + ' else ' + @colname + ' end '
  27060.         insert into #tempcmd (phase, cmdtext) values (9, @cmdpiece)
  27061.     end
  27062.  
  27063.     -- put in declaration for variable (phase 3) -- text and image get no variable
  27064.     if (@typename <> 'ntext' and @typename <> 'text' and @typename <> 'image')
  27065.     begin
  27066.         set @varname = '@l' + rtrim(@colordstr)
  27067.  
  27068.         set @cmdpiece = 'declare ' + @varname + ' ' + @typename + '
  27069. '
  27070.         insert into #tempcmd (phase, cmdtext) values (3, @cmdpiece)
  27071.  
  27072.         -- put in set piece to initialize variable to old value in select statement (phase 5)
  27073.         if @firstCol=1
  27074.         begin
  27075.             set @cmdpiece= ''
  27076.             set @firstCol= 0
  27077.         end
  27078.         else
  27079.             set @cmdpiece= ', '
  27080.  
  27081.         set @cmdpiece = @cmdpiece + @varname + ' = ' + @colname
  27082.         insert into #tempcmd (phase, cmdtext) values (5, @cmdpiece)
  27083.  
  27084.         -- put in if piece that compares old value with new, checks bit if argument is null
  27085.         if (@typename like '%char%')
  27086.         begin
  27087.             -- Compare binaries instead of variables so that case changes are caught as different
  27088.             set @littlecomp = 'convert(varbinary(' + rtrim(convert(nchar, @blen)) + '), ' + @argname + ')
  27089.                 = convert(varbinary(' + rtrim(convert(nchar, @blen)) + '), ' + @varname + ')'
  27090.         end
  27091.         else
  27092.         begin
  27093.             set @littlecomp = @argname + ' = ' + @varname
  27094.         end
  27095.  
  27096.         set @cmdpiece = '            if ' + @littlecomp + '
  27097.                 set @fset = 0
  27098.             else if ( ' + @varname + ' is null and ' + @argname + ' is null) 
  27099.                 set @fset = 0
  27100.             else if ' + @argname + ' is not null
  27101.                 set @fset = 1
  27102.             else if @setbm = 0x0
  27103.                 set @fset = 0
  27104.             else
  27105.                 exec @fset = dbo.sp_MStestbit @setbm, ' + @colordstr + '
  27106.             if @fset <> 0
  27107.                 begin
  27108.                 '
  27109.         insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece)
  27110.  
  27111.         if (@separate_update_needed = 0)
  27112.         begin
  27113.             if (@numbytes = 1)
  27114.             begin
  27115.                 -- no bytes on left or right of the byte being bitwise OR-ed.
  27116.                 set @cmdpiece = '
  27117.                     select @colbitmask = convert(varbinary(1), substring(@colbitmask, ' + @bytestr + ' , 1) | ' + @bitstr + ')
  27118.                     end
  27119.                     '
  27120.             end
  27121.             else 
  27122.             begin
  27123.                 -- there could be byte(s) on left and/or right of byte being bitwise OR-ed.
  27124.                 set @cmdpiece = '
  27125.                 select @colbitmask = 
  27126.                     convert
  27127.                     (
  27128.                     varbinary(' + convert(nvarchar, @numbytes) + '), '
  27129.                     + case when (@byteordinal = 1) then '' else ' convert(varbinary(' + convert(nvarchar, @byteordinal-1) + '), substring(@colbitmask, 1, ' + convert(nvarchar, @byteordinal-1) + ')) +' end +
  27130.                     ' convert(varbinary(1), substring(@colbitmask, ' + @bytestr + ' , 1) | ' + @bitstr + ') '
  27131.                     + case when (@byteordinal = @numbytes) then '' else ' + convert(varbinary(' + convert(nvarchar, @numbytes - @byteordinal) + '), substring(@colbitmask, ' + convert(nvarchar, @byteordinal+1) + ', ' + convert(nvarchar, @numbytes - @byteordinal) + ')) ' end + '
  27132.                     )
  27133.                 end 
  27134.                 '
  27135.             end
  27136.         end
  27137.         else
  27138.         begin
  27139.             set @cmdpiece = '
  27140.                     update ' + @qualified_name + ' set ' + @colname + ' = ' + @argname + ' where rowguidcol = @rowguid 
  27141.                     if (@@rowcount <> 1)
  27142.                     begin
  27143.                         set @errcode= 3
  27144.                         goto Failure
  27145.                     end
  27146.                 end 
  27147.                 '
  27148.         end
  27149.         insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece)
  27150.         select @has_updateable_columns_in_select_list = 1
  27151.     end
  27152.     else
  27153.     begin
  27154.         -- for text and image, we just test if argument is null and whether bit is set
  27155.         -- build conditional update (phase 7)
  27156.         set @cmdpiece =  '            if ' + @argname + ' is not null
  27157.                 set @fset = 1
  27158.             else if @setbm = 0x0
  27159.                 set @fset = 0
  27160.             else 
  27161.                 exec @fset = dbo.sp_MStestbit @setbm, ' + @colordstr + '
  27162.             if @fset <> 0
  27163.                 begin
  27164.                     update ' + @qualified_name + ' set ' + @colname + ' = ' + @argname + ' where rowguidcol = @rowguid 
  27165.                     if (@@rowcount <> 1)
  27166.                     begin
  27167.                         set @errcode= 3
  27168.                         goto Failure
  27169.                     end
  27170.                 end 
  27171.             '
  27172.         -- Now insert the command to temp table
  27173.         insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece)    
  27174.     end
  27175.     
  27176. Next_Column:        
  27177.     -- Advance loop to next column and repeat!
  27178.     select @colid = min (colid) from syscolumns where id = @sync_objid and colid > @colid and
  27179.         name not in (select name from syscolumns where id=@id and (iscomputed=1 OR type_name(xtype)='timestamp'))
  27180.     set @colname = NULL
  27181.     if (@colid is not null)
  27182.     begin
  27183.         select @colname = name, @typename = type_name(xtype), @blen = length,
  27184.             @prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale
  27185.             from syscolumns 
  27186.             where id = @sync_objid and colid = @colid
  27187.         select @status = status, @iscomputed=iscomputed, @xtype=xtype,
  27188.             @isrowguidcol = COLUMNPROPERTY(id, name, 'IsRowGuidCol') 
  27189.             from syscolumns 
  27190.             where id = @id and name = @colname
  27191.         
  27192.         if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
  27193.             set @len = @blen/2
  27194.         else
  27195.             set @len = @blen
  27196.         set @colordinal = @colordinal + 1
  27197.     end
  27198. end
  27199.  
  27200. -- Add dummy column list to select statement if there is no user updateable 
  27201. -- column.
  27202. if @has_updateable_columns_in_select_list = 0
  27203. begin
  27204.     insert into #tempcmd (phase, cmdtext) values (3, N'declare @l int')
  27205.     insert into #tempcmd (phase, cmdtext) values (5, N'@l = 1')
  27206. end
  27207.  
  27208. -- Now we select out the command text pieces in proper order so that our caller,
  27209. -- xp_execresultset will execute the command that creates the stored procedure.
  27210.  
  27211. set @cmdpiece = '        exec @retcode= dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, @colv, 2, ''' + convert(nvarchar(36),@pubid) + '''
  27212.         if @retcode<>0 or @@ERROR<>0
  27213.         begin
  27214.             set @errcode= 3
  27215.             goto Failure
  27216.         end
  27217.     end
  27218.     else
  27219.     begin
  27220.         set @errcode= 2
  27221.         goto Failure
  27222.     end
  27223.  
  27224.     commit transaction
  27225.  
  27226.  
  27227.     return(1)
  27228.  
  27229. Failure:
  27230.     rollback transaction sub
  27231.     commit transaction
  27232. '
  27233. insert into #tempcmd (phase, cmdtext) values (11, @cmdpiece)
  27234.  
  27235. exec dbo.sp_MScreatedupkeyupdatequery
  27236.             @tablename= @qualified_name,
  27237.             @tablenickstr= @tablenickstr,
  27238.             @phase= 11,
  27239.             @isconflictproc= 0
  27240.  
  27241. set @cmdpiece = '
  27242.     return @errcode'
  27243. insert into #tempcmd (phase, cmdtext) values (11, @cmdpiece)
  27244.  
  27245. select cmdtext from #tempcmd order by phase, step
  27246. drop table #tempcmd
  27247. drop table #coltab
  27248. go
  27249.  
  27250. exec dbo.sp_MS_marksystemobject sp_MSmakeupdateproc 
  27251. go
  27252. grant exec on dbo.sp_MSmakeupdateproc to public
  27253. go
  27254.  
  27255. raiserror('Creating procedure sp_MSmakeselectproc', 0,1)
  27256. GO
  27257.  
  27258. SET ANSI_NULLS ON 
  27259. SET QUOTED_IDENTIFIER ON
  27260. GO
  27261. create procedure sp_MSmakeselectproc 
  27262.     (@tablename sysname, @ownername sysname, @procname sysname, @pubid uniqueidentifier)
  27263. as
  27264. declare @retcode            smallint
  27265. declare @argname            nvarchar(10)
  27266. declare @varname            nvarchar(10)
  27267. declare @columns            varbinary(128)
  27268. declare @cmdpiece           nvarchar(4000)
  27269. declare @qualified_name     nvarchar(270)
  27270. declare @column_list        table (line_no int identity(1,1) primary key, line nvarchar(4000))
  27271. declare @littlecomp nvarchar(300)
  27272. declare @colid              int
  27273. declare @col_name           nvarchar(140)
  27274. declare @id                 int
  27275. declare @idstr              nvarchar(100)
  27276. declare @sync_objid         int
  27277. set nocount on
  27278.  
  27279. if @ownername is NULL or @ownername=''
  27280.     select @qualified_name = QUOTENAME(@tablename)
  27281. else    
  27282.     select @qualified_name = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename)
  27283.  
  27284. select @id = object_id(@qualified_name)
  27285.  
  27286. select @sync_objid=sync_objid from sysmergearticles where objid = @id and pubid=@pubid
  27287.  
  27288. set @idstr = rtrim(convert(nchar, @id)) 
  27289.  
  27290. /*
  27291. ** Include computed columns.
  27292. */
  27293. IF EXISTS (select name from syscolumns where id = @id and (name not in 
  27294.     (select name from syscolumns where id = @sync_objid)))
  27295.     OR exists (select name from syscolumns where id=@id and iscomputed=1)
  27296.     OR ObjectProperty(@id, 'TableHasTimestamp') = 1 
  27297. BEGIN
  27298.     DECLARE column_cursor CURSOR LOCAL FAST_FORWARD FOR
  27299.         select name from syscolumns where id=@id 
  27300.                 and iscomputed<>1 
  27301.                 and type_name(xtype) <>'timestamp' 
  27302.                 and name in (select name from syscolumns where id=@sync_objid)
  27303.     FOR READ ONLY
  27304.     open column_cursor
  27305.     fetch next from column_cursor into @col_name
  27306.     WHILE (@@fetch_status <> -1)
  27307.     BEGIN
  27308.             if ColumnProperty(@id, @col_name, 'isrowguidcol') = 1
  27309.                 select @col_name='rowguidcol'
  27310.             else
  27311.                 set @col_name = QUOTENAME(@col_name)
  27312.             if (select count(*) from @column_list) = 0
  27313.                 insert into @column_list(line) values (@col_name + '
  27314. ')
  27315.             else
  27316.                 insert into @column_list(line) values (', ' + @col_name + '
  27317. ')
  27318.             fetch next from column_cursor into @col_name            
  27319.     END
  27320.     close column_cursor
  27321.     deallocate column_cursor
  27322.  
  27323.     if (select count(*) from @column_list) = 0
  27324.     begin
  27325.         RAISERROR(21125, 16, -1)
  27326.         return (1)
  27327.     end
  27328. END
  27329. else 
  27330.     insert into @column_list(line) values('t.*')
  27331.  
  27332. /*
  27333. ** Check for dbo permission
  27334. */
  27335.     exec @retcode=sp_MSreplcheck_subscribe
  27336.     if @retcode<>0 or @@ERROR<>0 return (1)
  27337.  
  27338. set @cmdpiece= 'SET ANSI_NULLS ON SET QUOTED_IDENTIFIER ON'
  27339. exec (@cmdpiece)
  27340. if @@error<>0 return(1)
  27341.  
  27342. -- create temp table to select the command text out of
  27343. create table #tempcmd (step int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)
  27344.  
  27345. select @cmdpiece = '
  27346. Create procedure dbo.'  + QUOTENAME(@procname) + ' (@type int output, @rowguid uniqueidentifier=NULL) AS
  27347.     declare @retcode    int
  27348.         
  27349.     set nocount on
  27350.         
  27351.     -- role based security check
  27352.     if ({ fn ISPALUSER(''' + convert(nvarchar(36),@pubid) + ''') } <> 1)
  27353.     begin
  27354.         RAISERROR (14126, 11, -1)
  27355.         return (1)
  27356.     end
  27357.     
  27358.         
  27359.     if @type = 1
  27360.     begin
  27361.         select ' 
  27362. insert into #tempcmd (cmdtext) values (@cmdpiece)
  27363. insert into #tempcmd (cmdtext) select line from @column_list where line_no = 1
  27364. insert into #tempcmd (cmdtext) select 
  27365. '               ' + line from @column_list where line_no > 1 order by line_no asc
  27366. select @cmdpiece='              from ' + @qualified_name + ' t where rowguidcol = @rowguid
  27367.         if @@ERROR<>0 return(1)
  27368.     end
  27369.             
  27370.     else if @type < 4
  27371.     begin
  27372.         select c.tablenick, c.rowguid, c.generation, c.lineage, c.colv1
  27373.                ,' 
  27374. insert into #tempcmd (cmdtext) values (@cmdpiece)
  27375. insert into #tempcmd (cmdtext) select line from @column_list where line_no = 1
  27376. insert into #tempcmd (cmdtext) select 
  27377. '              ' + line from @column_list where line_no > 1 order by line_no asc
  27378. select @cmdpiece='          from ' +
  27379.                  @qualified_name + ' t,  #cont c where
  27380.                t.rowguidcol = c.rowguid
  27381.          order by t.rowguidcol 
  27382.         if @@ERROR<>0 return(1)
  27383.     end
  27384.  
  27385.     else if @type = 4
  27386.     begin
  27387.         set @type = 0
  27388.         if exists (select * from ' + @qualified_name + ' where rowguidcol = @rowguid)
  27389.             set @type = 3
  27390.         if @@ERROR<>0 return(1)
  27391.     end
  27392.  
  27393.     else if @type = 5
  27394.     begin
  27395.         delete ' + @qualified_name + ' where rowguidcol = @rowguid
  27396.         if @@ERROR<>0 return(1)
  27397.     end
  27398.  
  27399.     else if @type = 6 -- sp_MSenumcolumns
  27400.     begin
  27401.         select ' 
  27402. insert into #tempcmd (cmdtext) values (@cmdpiece)
  27403. insert into #tempcmd (cmdtext) select line from @column_list where line_no = 1
  27404. insert into #tempcmd (cmdtext) select 
  27405. '               ' + line from @column_list where line_no > 1 order by line_no asc
  27406. select @cmdpiece='              from ' + @qualified_name + ' t where 1=2
  27407.         if @@ERROR<>0 return(1)
  27408.     end
  27409.  
  27410.     else if @type = 7 -- sp_MSlocktable
  27411.     begin
  27412.         select 1 from ' + @qualified_name + '(tablock holdlock) where 1 = 2
  27413.         if @@ERROR<>0 return(1)
  27414.     end
  27415.  
  27416.     else if @type = 8 -- put update lock
  27417.     begin
  27418.         if not exists (select * from ' + @qualified_name + '(UPDLOCK HOLDLOCK) where rowguidcol = @rowguid)
  27419.         begin
  27420.             RAISERROR(20031 , 16, -1)
  27421.             return(1)
  27422.         end
  27423.     end
  27424.         
  27425.     return(0)'
  27426.  
  27427. insert into #tempcmd (cmdtext) values (@cmdpiece)
  27428. select cmdtext from #tempcmd order by step
  27429. drop table #tempcmd
  27430. go
  27431.             
  27432. exec dbo.sp_MS_marksystemobject sp_MSmakeselectproc 
  27433. go
  27434. grant exec on dbo.sp_MSmakeselectproc to public
  27435. go
  27436.  
  27437. SET ANSI_NULLS OFF
  27438. go
  27439. raiserror('Creating procedure sp_MSdropconstraints', 0,1)
  27440. GO
  27441.  
  27442. -- This will be called merge at the subscriber side, check for dbo permission
  27443. create procedure sp_MSdropconstraints
  27444.       @table sysname
  27445. as
  27446.     declare @const_name nvarchar(140)
  27447.     declare @objid int
  27448.     declare @retcode int
  27449.     
  27450.     /*
  27451.     ** Check for subscribing permission
  27452.     */
  27453.     exec @retcode=sp_MSreplcheck_subscribe
  27454.     if @retcode<>0 or @@ERROR<>0 return (1)
  27455.  
  27456.     select @table=QUOTENAME(@table)
  27457.     
  27458.     set @objid = object_id(@table)
  27459.     if @objid is null
  27460.         select @objid = id from sysobjects where name=@table
  27461.     if @objid is NULL
  27462.         return (1)
  27463.     select @const_name = QUOTENAME(object_name(constid)) from 
  27464.         sysreferences where fkeyid = @objid
  27465.     while @const_name is not null
  27466.         begin
  27467.             exec ('alter table ' + @table +
  27468.                 ' drop constraint ' + @const_name)
  27469.             if @@ERROR <> 0
  27470.                 return (1)
  27471.             set @const_name = NULL
  27472.             select @const_name = QUOTENAME(object_name(constid)) from 
  27473.                 sysreferences where fkeyid = @objid
  27474.         end
  27475.  
  27476.     return (0)        
  27477. go
  27478.  
  27479. exec dbo.sp_MS_marksystemobject sp_MSdropconstraints
  27480. go
  27481. grant exec on dbo.sp_MSdropconstraints to public
  27482. go
  27483.  
  27484. raiserror('Creating procedure sp_MSinsertschemachange', 0,1)
  27485. GO
  27486.  
  27487. CREATE PROCEDURE sp_MSinsertschemachange(
  27488.     @pubid            uniqueidentifier,
  27489.     @artid            uniqueidentifier = NULL, /* Can be NULL for directory commands */
  27490.     @schemaversion     int,
  27491.     @schemaguid        uniqueidentifier,
  27492.     @schematype        int,
  27493.     @schematext        nvarchar(2000)
  27494.     )
  27495. as
  27496.     declare @retcode            int
  27497.     declare @constraintname        sysname    
  27498.     declare @owner                sysname
  27499.     declare @tablename            sysname
  27500.     declare @qualname            nvarchar(270)
  27501.     declare @objid                int
  27502.     declare @alter_table_type    int
  27503.     /*
  27504.     ** Check for subscribing permission
  27505.     */
  27506.     exec @retcode=sp_MSreplcheck_subscribe
  27507.     if @retcode<>0 or @@ERROR<>0 return (1)
  27508.     
  27509.     select @alter_table_type = 11
  27510.     
  27511.     /* Parameter validation */
  27512.     if (@schemaversion is null)
  27513.         begin
  27514.         RAISERROR(14043, 16, -1, '@schemaversion')
  27515.         return (1)
  27516.         end
  27517.  
  27518.     if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
  27519.         begin
  27520.         RAISERROR(20054 , 16, -1)
  27521.         return (1)
  27522.         end
  27523.  
  27524.     /*
  27525.     ** Special case: for push subscription, reinit-with-upload, we do not want to cleanup subscriber side
  27526.     ** cause we need to upload; however we still need to apply alter-table. To avoid duplicate key insert
  27527.     ** failure, we no-OP this insert of alter-table schema.
  27528.     */
  27529.     if @schematype=@alter_table_type and exists 
  27530.         (select * from sysmergeschemachange where pubid=@pubid and schemaversion=@schemaversion)
  27531.         return (1)
  27532.         
  27533.  
  27534.     insert into sysmergeschemachange with (HOLDLOCK TABLOCKX) (pubid, artid, schemaversion, schemaguid, schematype, schematext)
  27535.              values (@pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext) 
  27536.     if @@error <> 0        
  27537.         begin
  27538.             RAISERROR(21305 , 16, -1)
  27539.             return (1)
  27540.         end
  27541.     /* update the schema version and schemaguid in MSmerge_replinfo */        
  27542.     declare @my_nickname int
  27543.     declare @srvid int
  27544.     select @srvid = 0
  27545.     declare @repid         uniqueidentifier
  27546.     select  @my_nickname = replnickname,  @repid = repid from MSmerge_replinfo 
  27547.         where repid in (select subid from sysmergesubscriptions
  27548.             where srvid = @srvid and db_name = DB_NAME() and pubid = @pubid)
  27549.  
  27550.     update MSmerge_replinfo set schemaversion = @schemaversion, schemaguid = @schemaguid where repid = @repid and (schemaversion<@schemaversion or schemaversion is NULL)
  27551.     if @@error <> 0        
  27552.         begin
  27553.             RAISERROR(21305 , 16, -1)
  27554.             return (1)
  27555.         end
  27556.  
  27557.     /* only delete the publisher side check constraint at subscriber side */
  27558.     if @schematype=15 and 
  27559.         not exists (select * from sysmergepublications where  pubid=@pubid and LOWER(publisher)=LOWER(@@SERVERNAME)
  27560.             and publisher_db=db_name())
  27561.     begin
  27562.         select @objid=objid from sysmergearticles where artid=@artid and pubid=@pubid
  27563.         select @owner = user_name(uid) from sysobjects where id = @objid
  27564.         select @tablename = object_name(@objid)
  27565.         select @qualname = QUOTENAME(@owner) + '.' + QUOTENAME(@tablename)
  27566.         /*
  27567.         ** This is to removed CHECK constraint we accidentally propagated to subscriber side on identity check
  27568.         */
  27569.         select @constraintname = 'repl_identity_range_pub_' + convert(nvarchar(36), @artid)
  27570.         select @constraintname = REPLACE(@constraintname, '-', '_')
  27571.         if exists (select * from sysobjects where name = @constraintname and xtype='C')
  27572.         begin
  27573.             exec ('alter table '+ @qualname + ' drop constraint ' + @constraintname)
  27574.             if @@ERROR<>0
  27575.                 return (1)
  27576.         end
  27577.  
  27578.         select @constraintname = 'repl_identity_range_repub_' + convert(nvarchar(36), @artid)
  27579.         select @constraintname = REPLACE(@constraintname, '-', '_')
  27580.         if exists (select * from sysobjects where name = @constraintname and xtype='C')
  27581.         begin
  27582.             exec ('alter table '+ @qualname + ' drop constraint ' + @constraintname)
  27583.             if @@ERROR<>0
  27584.                 return (1)
  27585.         end
  27586.     end
  27587.     
  27588.     return (0)        
  27589. go
  27590. exec dbo.sp_MS_marksystemobject sp_MSinsertschemachange
  27591. go
  27592. grant exec on dbo.sp_MSinsertschemachange to public
  27593. go
  27594.  
  27595. raiserror('Creating procedure sp_MSgetviewcolumnlist', 0, 1)
  27596. GO
  27597.  
  27598. create procedure sp_MSgetviewcolumnlist(
  27599. @pubid                uniqueidentifier,
  27600. @source_objid        int,
  27601. @column_list         nvarchar(4000) OUTPUT
  27602. )
  27603. AS
  27604. /* 
  27605. ** if it is not vertically partitioned, then get all columns 
  27606. ** else get the column list as given in columns of sysmergearticles
  27607. */
  27608. declare @bitset        int
  27609. declare @columns    varbinary(125)
  27610. declare @setcolcnt    int
  27611. declare @colcnt        int
  27612. declare @colname    nvarchar(140)
  27613. declare @colid        int
  27614.  
  27615. select @columns = columns from sysmergearticles where objid = @source_objid and pubid=@pubid
  27616. select @column_list = ''
  27617. select @setcolcnt    = 0
  27618. select @colcnt = count(*) from syscolumns where id = @source_objid
  27619. declare collist CURSOR LOCAL FAST_FORWARD FOR 
  27620.        select name, colid from syscolumns where id = @source_objid and iscomputed <> 1 and type_name(xtype) <> 'timestamp' order by colid ASC
  27621. FOR READ ONLY
  27622. open collist
  27623. fetch collist into @colname, @colid
  27624. WHILE (@@fetch_status <> -1)
  27625. BEGIN
  27626.     set @bitset = 1
  27627.     if @columns is NOT NULL
  27628.         exec @bitset = sp_MStestbit @columns, @colid
  27629.     if @bitset<>0
  27630.     begin
  27631.         select @colname = QUOTENAME(@colname) --previously we use rowguidcol to replace 'rowguid'
  27632.         if @column_list=''                      --which can cause problems and is not necessary.
  27633.             select @column_list = @colname
  27634.         else
  27635.             select @column_list = @column_list + ', ' + @colname    
  27636.         select @setcolcnt = @setcolcnt + 1
  27637.     end                    
  27638. fetch next from collist into @colname, @colid            
  27639. END
  27640. close collist
  27641. deallocate collist
  27642. if @setcolcnt = @colcnt
  27643.     select @column_list = ' * '
  27644. return 0    
  27645. GO
  27646. exec dbo.sp_MS_marksystemobject sp_MSgetviewcolumnlist 
  27647. go
  27648.  
  27649.  
  27650. raiserror('Creating procedure sp_MSvalidatearticle', 0, 1)
  27651. GO
  27652.  
  27653. create procedure sp_MSvalidatearticle
  27654.     @artid         uniqueidentifier,
  27655.     @pubid        uniqueidentifier,
  27656.     @expected_rowcount bigint = NULL OUTPUT,
  27657.     @expected_checksum numeric = NULL OUTPUT,
  27658.     @validation_type int = NULL,
  27659.     @full_or_fast tinyint = 2
  27660. as
  27661. -- get name of sync object and owner
  27662.     declare @objid int
  27663.     declare @syncobjid int
  27664.     declare @owner sysname
  27665.     declare @object sysname
  27666.     declare @view_type tinyint
  27667.     declare @temp_view tinyint
  27668.     declare @retcode int
  27669.     declare @rowcount_only int
  27670.     declare @source_objid int
  27671.     declare @column_list nvarchar(4000)
  27672.     /*
  27673.     ** Check to see if current publication has permission
  27674.     */
  27675.     if ({ fn ISPALUSER(@pubid) } <> 1)
  27676.     begin    
  27677.         RAISERROR (14126, 11, -1)
  27678.         return (1)
  27679.     end
  27680.     
  27681.     /* 
  27682.     The @rowcount_only param is overloaded for shiloh release due to backward compatibility concerns.
  27683.     In shiloh, the checksum functionality has changed.   So 7.0 subscribers will have the old checksum 
  27684.     routines, which generate different CRC values, and do not have functionality for vertical partitions,
  27685.     or logical table structures where column offsets differ (due to ALTER TABLEs that DROP and ADD columns).
  27686.  
  27687.     In 7.0, this was a bit column.  0 meant do not do just a rowcount - do a checksum.  1 meant just do a 
  27688.     rowcount.
  27689.  
  27690.     For Shiloh, this parameter is changed to a smallint with these options:
  27691.     0 - Do a 7.0 compatible checksum
  27692.     1 - Do a rowcount check only
  27693.     2 - Use new Shiloh checksum functionality.  Note that because 7.0 subscribers will 
  27694.     take this parameter as a bit type, not a smallint, it will be interpreted as simply
  27695.     ON.  That means that passing a 2, and having a 7.0 subscriber, will result in the 7.0
  27696.     subscriber doing only rowcount validation.   The Shiloh subscribers will do both
  27697.     rowcount and checksum.  If you want 7.0 subscribers to do checksum validation, use 
  27698.     the value of 0 for this parameter.   Shiloh subscribers can do the 7.0 compatible 
  27699.     checksum, but that checksum has the same 7.0 limitations for vertical partitions 
  27700.     and differences in physical table structure.)
  27701.     */
  27702.     if @validation_type = 3
  27703.         set @rowcount_only  = 2
  27704.     else if @validation_type = 2
  27705.         set @rowcount_only  = 0
  27706.     else
  27707.         set @rowcount_only  = 1
  27708.  
  27709.               
  27710.     select @syncobjid = sync_objid, @objid = objid, @view_type = view_type from
  27711.         sysmergearticles where pubid = @pubid and artid = @artid
  27712.     select @source_objid = @objid        
  27713.     if (@syncobjid is not null and @syncobjid <> 0)
  27714.         set @objid = @syncobjid
  27715.         
  27716.     select @object = name, @owner = user_name(uid) from sysobjects where id = @objid
  27717.     
  27718. --  if sync object is a temp view, we can't do this...
  27719.     set @temp_view = 2
  27720.     if @view_type = @temp_view
  27721.         begin
  27722.         RAISERROR (20069, 16, -1)
  27723.         return 1
  27724.         end
  27725.     else if (@view_type = 1 and @rowcount_only = 0)
  27726.         begin
  27727.         RAISERROR (21017, 16, -1)
  27728.         return 1
  27729.         end
  27730.  
  27731.     exec @retcode = sp_MSgetviewcolumnlist @pubid, @source_objid, @column_list OUTPUT
  27732.     if @@ERROR<>0 OR @retcode <> 0
  27733.         return @retcode
  27734.  
  27735. --  call sp_table_validation
  27736.     exec @retcode = dbo.sp_table_validation @object, @expected_rowcount OUTPUT, @expected_checksum  OUTPUT, @rowcount_only, @owner, @full_or_fast, 0, NULL, @column_list
  27737.     if @@error<>0 return(1)
  27738.     return @retcode
  27739.     
  27740. GO
  27741. exec dbo.sp_MS_marksystemobject sp_MSvalidatearticle
  27742. go
  27743. grant exec on dbo.sp_MSvalidatearticle to public
  27744. go
  27745.  
  27746. raiserror('Creating procedure sp_MSsubscriptionvalidated', 0, 1)
  27747. GO
  27748.  
  27749. create procedure sp_MSsubscriptionvalidated
  27750.     @subid         uniqueidentifier,
  27751.     @pubid        uniqueidentifier,
  27752.     @log_attempt    bit = 0
  27753. as
  27754.     declare @now datetime
  27755.     declare @retcode int
  27756.  
  27757.     select @now=getdate()
  27758.     
  27759.     if ({ fn ISPALUSER(@pubid) } <> 1)
  27760.     begin    
  27761.         RAISERROR (14126, 11, -1)
  27762.         return (1)
  27763.     end
  27764.     
  27765.     if @log_attempt=0
  27766.         update sysmergesubscriptions set last_validated = @now, attempted_validate=@now
  27767.             where subid = @subid and pubid = @pubid
  27768.     else
  27769.         update sysmergesubscriptions set attempted_validate = @now
  27770.             where subid = @subid and pubid = @pubid        
  27771.     if @@rowcount <> 1 or @@error <> 0
  27772.         begin
  27773.         RAISERROR (20070, 16, -1)
  27774.         return (1)
  27775.         end
  27776.     return (0)
  27777. GO
  27778. exec dbo.sp_MS_marksystemobject sp_MSsubscriptionvalidated
  27779. go
  27780. grant exec on dbo.sp_MSsubscriptionvalidated to public
  27781.  
  27782. raiserror('Creating procedure sp_MSdroparticletombstones', 0, 1)
  27783. GO
  27784.  
  27785. create procedure sp_MSdroparticletombstones
  27786.     @artid         uniqueidentifier
  27787. as
  27788.     declare @tablenick int
  27789.     declare @retcode int
  27790.     
  27791.     -- security check
  27792.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @artid=@artid
  27793.     if @@error <> 0 or @retcode <> 0
  27794.         return 1
  27795.  
  27796.     select @tablenick = nickname from sysmergearticles where artid = @artid
  27797.     if @tablenick is not null
  27798.     begin
  27799.         delete from dbo.MSmerge_tombstone where tablenick = @tablenick
  27800.         delete from dbo.MSmerge_contents where tablenick = @tablenick
  27801.         delete from dbo.MSmerge_genhistory where art_nick=@tablenick
  27802.     end
  27803.     return (0)
  27804. GO
  27805. exec dbo.sp_MS_marksystemobject sp_MSdroparticletombstones
  27806. go
  27807. grant exec on dbo.sp_MSdroparticletombstones to public
  27808.  
  27809. raiserror('Creating procedure sp_MSproxiedmetadata', 0, 1)
  27810. GO
  27811.  
  27812. create procedure sp_MSproxiedmetadata
  27813.     @tablenick    int,
  27814.     @rowguid    uniqueidentifier,
  27815.     @lineage    varbinary(256),
  27816.     @colv        varbinary(2048)
  27817. as
  27818.     declare @old_lin varbinary(256)
  27819.     declare @old_colv varbinary(2048)
  27820.     declare @retcode int
  27821.  
  27822.     -- security check
  27823.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick=@tablenick
  27824.     if @@error <> 0 or @retcode <> 0
  27825.         return 1
  27826.  
  27827. Loop:
  27828.     set @old_lin= NULL
  27829.     select @old_lin = lineage, @old_colv = colv1 from dbo.MSmerge_contents where
  27830.         tablenick = @tablenick and rowguid = @rowguid
  27831.  
  27832.     if (@old_lin IS NOT NULL)
  27833.     begin
  27834.         exec @retcode= master..xp_proxiedmetadata @lineage out, @colv out, @old_lin, @old_colv
  27835.         if @@error<>0 or @retcode<>0
  27836.         begin
  27837.             return(1)
  27838.         end
  27839.         update dbo.MSmerge_contents set lineage = @lineage, colv1 = @colv
  27840.             where tablenick = @tablenick and rowguid = @rowguid and lineage = @old_lin
  27841.         if @@rowcount = 0 and @@error = 0 goto Loop
  27842.     end
  27843.     else
  27844.     begin
  27845.         select @old_lin = lineage from dbo.MSmerge_tombstone where
  27846.             tablenick = @tablenick and rowguid = @rowguid
  27847.         if (@old_lin IS NULL)
  27848.             return (0)
  27849.  
  27850.         exec @retcode= master..xp_proxiedmetadata @lineage out, @colv out, @old_lin, NULL
  27851.         if @@error<>0 or @retcode<>0
  27852.         begin
  27853.             return(1)
  27854.         end
  27855.         update dbo.MSmerge_tombstone set lineage = @lineage
  27856.             where tablenick = @tablenick and rowguid = @rowguid and lineage = @old_lin
  27857.         if @@rowcount = 0 and @@error = 0 goto Loop
  27858.     end
  27859.  
  27860.     return (0)
  27861. GO
  27862. exec dbo.sp_MS_marksystemobject sp_MSproxiedmetadata
  27863. grant exec on dbo.sp_MSproxiedmetadata to public
  27864. go
  27865.  
  27866. raiserror('Creating procedure sp_MScontractsubsnb', 0,1)
  27867. GO
  27868.  
  27869. create PROCEDURE sp_MScontractsubsnb 
  27870.     (@pubid uniqueidentifier,
  27871.      @tablenick int,
  27872.      @basetable nvarchar(270))
  27873. AS
  27874.     declare        @filter_clause    nvarchar(4000)
  27875.     declare     @join_nick int
  27876.     declare        @jointable        nvarchar(270)
  27877.     declare     @filterid int
  27878.     declare     @retcode int
  27879.     declare     @tablenickstr nvarchar(10)
  27880.     set @tablenickstr = convert(nchar(10), @tablenick)
  27881.     
  27882.     /* First, try to remove rows from notbelong based on the article filter, if there is one */
  27883.     select @filter_clause = subset_filterclause from sysmergearticles where
  27884.         pubid = @pubid and nickname = @tablenick
  27885.     if len(@filter_clause) > 0
  27886.         begin
  27887.         exec ('delete from #notbelong with (paglock) where tablenick = ' + @tablenickstr + ' and rowguid in
  27888.                 (select RowGuidCol from ' + @basetable + ' where ' + @filter_clause + ')' )
  27889.         if @@error<>0 return(1)
  27890.         end
  27891.  
  27892.     /* Now loop over any join filters that have this as the base_table */
  27893.     select @filterid = min(join_filterid) from sysmergesubsetfilters
  27894.         where pubid = @pubid and art_nickname = @tablenick
  27895.     while @filterid is not null
  27896.         begin
  27897.         /* Get joining table and filter clause */
  27898.         select @join_nick = join_nickname, @filter_clause = join_filterclause
  27899.                 from sysmergesubsetfilters where pubid = @pubid and join_filterid = @filterid
  27900.         exec @retcode = dbo.sp_MStablenamefromnick @join_nick, @jointable out, @pubid
  27901.         if @@error<>0 or @retcode<>0 return(1)
  27902.  
  27903.         /* Exec query to remove rows from #notbelong that still belong to partial */
  27904.         exec ('delete from #notbelong with (paglock) where tablenick = ' + @tablenickstr + ' and rowguid in
  27905.                 (select ' + @basetable + '.RowGuidCol from ' + @basetable + ', ' +
  27906.                 @jointable + ' where (' + @filter_clause + ') and ' + @jointable +
  27907.                 '.RowGuidCol not in (select rowguid from #notbelong))')
  27908.         if @@error<>0 return(1)
  27909.  
  27910.         /* Find the next filter that might apply */
  27911.         select @filterid = min(join_filterid) from sysmergesubsetfilters
  27912.             where pubid = @pubid and art_nickname = @tablenick and join_filterid > @filterid
  27913.         end
  27914.         return(0)
  27915. go
  27916.  
  27917. exec dbo.sp_MS_marksystemobject sp_MScontractsubsnb 
  27918. go
  27919.  
  27920. raiserror('Creating procedure sp_MSexpandsubsnb', 0,1)
  27921. GO
  27922.  
  27923. create PROCEDURE sp_MSexpandsubsnb (@pubid uniqueidentifier)
  27924. AS
  27925.     declare @filterid int
  27926.     declare @base_nick int
  27927.     declare @join_nick int
  27928.     declare @basetable nvarchar(270)
  27929.     declare @jointable nvarchar(270)
  27930.     declare @join_clause nvarchar(4000)
  27931.     declare @retcode int
  27932.     declare @error int
  27933.     declare @rowcount int
  27934.     declare @base_nickstr nvarchar(10)
  27935.     declare @join_unique_key int
  27936.  
  27937.     /* get first filter to expand on */
  27938.     select @filterid = min(join_filterid) from sysmergesubsetfilters f, #notbelong nb
  27939.         where pubid = @pubid and nb.tablenick = f.join_nickname and f.join_filterid > nb.flag
  27940.  
  27941.     while @filterid is not null
  27942.         begin
  27943.         /* get join clause and tables for this filter */
  27944.         select @join_nick = join_nickname, @join_clause = join_filterclause,
  27945.             @base_nick = art_nickname, @join_unique_key = join_unique_key from sysmergesubsetfilters where
  27946.                 pubid = @pubid and join_filterid = @filterid
  27947.         exec @retcode = dbo.sp_MStablenamefromnick @join_nick, @jointable out, @pubid
  27948.         if @@error<>0 or @retcode<>0 return(1)
  27949.         exec @retcode = dbo.sp_MStablenamefromnick @base_nick, @basetable out, @pubid
  27950.         if @@error<>0 or @retcode<>0 return(1)
  27951.         set @base_nickstr = convert(nchar(10), @base_nick)
  27952.  
  27953.         /* Mark rows so that we know we've expanded those rows for this filter */
  27954.         update #notbelong set flag = @filterid where flag < @filterid
  27955.         
  27956.         /* exec an insert/select query to expand #notbelong */
  27957.         exec ('insert into #notbelong (tablenick, rowguid, flag) select distinct ' +
  27958.                 @base_nickstr + ', ' + @basetable + '.RowGuidCol, 0 from ' + @basetable + 
  27959.                 ', ' + @jointable + ' where ( ' + @jointable + '.RowGuidCol in 
  27960.                     (select rowguid from #notbelong) ) and (' + @join_clause + ')')
  27961.         select @error=@@error, @rowcount=@@rowcount
  27962.         if @error<>0 return(1)
  27963.         /* 
  27964.         ** if any rows inserted, try to contract the #notbelong table.
  27965.         ** Only join filters that are non unique need to contract the 
  27966.         ** NOTBELONGS table - 
  27967.         */
  27968.         if @rowcount <> 0 and @join_unique_key = 0
  27969.         begin
  27970.             exec @retcode = dbo.sp_MScontractsubsnb @pubid, @base_nick, @basetable
  27971.             if @@error<>0 or @retcode<>0 return(1)
  27972.         end
  27973.         
  27974.         /* get next filter to expand with */
  27975.         select @filterid = min(join_filterid) from sysmergesubsetfilters f, #notbelong nb
  27976.             where pubid = @pubid and nb.tablenick = f.join_nickname and f.join_filterid > nb.flag
  27977.         end
  27978.  
  27979.         return(0)
  27980. go
  27981.  
  27982. exec dbo.sp_MS_marksystemobject sp_MSexpandsubsnb 
  27983. go
  27984. raiserror('Creating procedure sp_MSdelsubrows', 0,1)
  27985. GO
  27986.  
  27987. create PROCEDURE sp_MSdelsubrows 
  27988.     (@rowguid         uniqueidentifier,
  27989.     @tablenick     int,
  27990.     @metadata_type tinyint, /* 0 - Missing, 1 - Tombstone, 2 - Contents, 3 - ContentsDeferred, 6 - system delete */
  27991.     @lineage_old varbinary(255),
  27992.     @generation int,
  27993.     @lineage_new varbinary(255),
  27994.     @pubid uniqueidentifier = NULL,
  27995.     @rowsdeleted INT = NULL OUTPUT)
  27996.  
  27997. as
  27998.     declare @match             int
  27999.     declare @errcode        int
  28000.     declare @new_metatype    tinyint
  28001.     declare @retcode         smallint
  28002.     declare @reason         nvarchar(255)
  28003.     declare @procname         sysname
  28004.     declare @tnstr            nvarchar(11)
  28005.     declare @error int, @rowcount int
  28006.     
  28007.     /* By default this sp should delete exactly one row */
  28008.     set    @rowsdeleted = 1
  28009.     
  28010.     /*
  28011.     ** Check to see if current publication has permission
  28012.     */
  28013.     if @pubid is NULL
  28014.     begin
  28015.         exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick = @tablenick
  28016.         if @retcode<>0 or @@ERROR<>0 return (0)
  28017.     end
  28018.     else
  28019.     begin
  28020.         if ({ fn ISPALUSER(@pubid) } <> 1)
  28021.         begin    
  28022.             RAISERROR (14126, 11, -1)
  28023.             return (1)
  28024.         end
  28025.     end
  28026.         
  28027.     /* Parameter validation */
  28028.     if (@rowguid is null)
  28029.     begin
  28030.         RAISERROR(14043, 16, -1, '@rowguid')
  28031.         return (0)
  28032.     end
  28033.     if (@tablenick is null)
  28034.     begin
  28035.         RAISERROR(14043, 16, -1, '@tablenick')
  28036.         return (0)
  28037.     end
  28038.     if (@lineage_new is null)
  28039.     begin
  28040.         RAISERROR(14043, 16, -1, '@lineage_new')
  28041.         return (0)
  28042.     end
  28043.  
  28044.     -- Are we just changing the type of a tombstone?
  28045.     if (@metadata_type = 5 or @metadata_type = 1)
  28046.     begin
  28047.         if exists (select * from dbo.MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)
  28048.         begin
  28049.             
  28050.             if (@metadata_type = 5)
  28051.                 set @reason = formatmessage (20563) -- Remove from partial
  28052.             else if (@metadata_type = 1)
  28053.                 set @reason = formatmessage (20562) -- User delete
  28054.  
  28055.             update dbo.MSmerge_tombstone 
  28056.                 set type = @metadata_type, reason = @reason, generation = @generation, lineage = @lineage_new 
  28057.                 where rowguid = @rowguid and tablenick = @tablenick
  28058.         return 1
  28059.         end
  28060.     end
  28061.     
  28062.     -- Are we just changing the type of a tombstone?
  28063.     else if (@metadata_type = 6)
  28064.     begin
  28065.         if exists (select * from dbo.MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)
  28066.         begin
  28067.             set @reason = formatmessage (20564) -- System deleted
  28068.             update dbo.MSmerge_tombstone set type = @metadata_type, reason = @reason 
  28069.                 where rowguid = @rowguid and tablenick = @tablenick
  28070.             return 1
  28071.         end
  28072.     end
  28073.  
  28074.     -- begin transaction and lock row that we plan to delete
  28075.     begin transaction
  28076.     save tran sp_MSdelsubrows
  28077.  
  28078.     select @procname = select_proc from sysmergearticles where nickname = @tablenick and pubid = @pubid
  28079.     exec @retcode = @procname @type =8, @rowguid=@rowguid
  28080.     IF @@ERROR<>0 or @retcode<>0
  28081.     begin
  28082.         set @errcode= 0
  28083.         goto Failure
  28084.     end
  28085.         
  28086.     if @metadata_type = 5
  28087.     begin
  28088.         set @match = 1
  28089.         set @new_metatype = 5
  28090.     end
  28091.     else if @metadata_type = 6
  28092.     begin
  28093.         set @match = 1
  28094.         set @new_metatype = 6
  28095.     end
  28096.     else if @metadata_type = 7
  28097.     begin
  28098.         set @match = 1
  28099.         set @new_metatype = 7
  28100.     end
  28101.     else
  28102.     begin
  28103.         exec @retcode=sp_MScheckmetadatamatch @metadata_type, @rowguid, @tablenick, @lineage_old, @match output
  28104.         IF @@ERROR<>0 or @retcode<>0
  28105.         begin
  28106.             set @errcode= 0
  28107.             goto Failure
  28108.         end
  28109.  
  28110.         set @new_metatype = 1
  28111.     end
  28112.  
  28113.     if (@match = 1)
  28114.     begin
  28115.         
  28116.         /* If there are any joinfilters with this as the join table, try to expand to deleting
  28117.         ** a set of related rows.
  28118.         */
  28119.         if (exists (select * from sysmergesubsetfilters where pubid = @pubid and join_nickname = @tablenick))
  28120.         begin
  28121.             declare @tn int
  28122.             declare @table_name nvarchar(270)
  28123.             
  28124.             select @rowsdeleted = 0
  28125.  
  28126.             set @reason = formatmessage (20563) -- Moved out of partial range
  28127.             /* create temp and put in our tablenick, rowguid */
  28128.             create table #notbelong (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, flag int NOT NULL)
  28129.             create index #indnbelong on #notbelong (tablenick, rowguid)
  28130.             insert into #notbelong (tablenick, rowguid, flag) values
  28131.                     (@tablenick, @rowguid, 0)
  28132.             
  28133.             /* call expand proc */
  28134.             exec @retcode = dbo.sp_MSexpandsubsnb @pubid
  28135.             IF @@ERROR<>0 or @retcode<>0
  28136.             begin
  28137.                 set @errcode= 0
  28138.                 goto Failure
  28139.             end
  28140.         
  28141.             select @tn = max(tablenick) from #notbelong where flag > -1
  28142.             while @tn is not null
  28143.             begin
  28144.                 select @tnstr = convert(nvarchar(11), @tn)
  28145.  
  28146.                 exec @retcode = dbo.sp_MStablenamefromnick @tn, @table_name out, @pubid
  28147.                 -- delete all rows indicated by the temp table
  28148.                 IF @@ERROR<>0 or @retcode<>0
  28149.                 begin
  28150.                     set @errcode= 0
  28151.                     goto Failure
  28152.                 end
  28153.                 exec ('delete from ' + @table_name + ' where RowGuidCol in 
  28154.                     (select rowguid from #notbelong where tablenick = ' + @tnstr + ')' )
  28155.                 select @error=@@error, @rowcount=@@rowcount
  28156.                 IF @error<>0
  28157.                 begin
  28158.                     set @errcode= 0
  28159.                     goto Failure
  28160.                 end
  28161.  
  28162.                 select @rowsdeleted = @rowsdeleted + @rowcount
  28163.             
  28164.                 -- move on to next nickname - decreasing makes delete order correct
  28165.                 update #notbelong set flag = -1 where tablenick = @tn
  28166.                 select @tn = max(tablenick) from #notbelong where flag > -1
  28167.             end
  28168.  
  28169.             -- change tombstone type for those rows
  28170.             update dbo.MSmerge_tombstone 
  28171.             set type = 5, reason = @reason 
  28172.             from #notbelong nb, dbo.MSmerge_tombstone ts
  28173.             where ts.tablenick = nb.tablenick and
  28174.             ts.rowguid = nb.rowguid
  28175.  
  28176.             drop table #notbelong
  28177.             exec @retcode= dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, NULL, @new_metatype, @pubid
  28178.             IF @@ERROR<>0 or @retcode<>0
  28179.             begin
  28180.                 set @errcode= 0
  28181.                 goto Failure
  28182.             end
  28183.         end
  28184.         else
  28185.         begin
  28186.             
  28187.             -- select_proc makes a delete with @type = 5, despite its name. 
  28188.             exec @retcode = @procname @type =5, @rowguid=@rowguid
  28189.             select @error= @@error, @rowcount= @@rowcount
  28190.             IF @error<>0 or @retcode<>0
  28191.             begin
  28192.                 set @errcode= 0
  28193.                 goto Failure
  28194.             end
  28195.         
  28196.             if (@rowcount = 1)
  28197.             begin
  28198.                 exec @retcode= dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, NULL, @new_metatype, @pubid
  28199.                 IF @@ERROR<>0 or @retcode<>0
  28200.                 begin
  28201.                     set @errcode= 0
  28202.                     goto Failure
  28203.                 end
  28204.             end
  28205.             else
  28206.                 goto Failure
  28207.         end
  28208.     end
  28209.     else
  28210.     begin
  28211.         set @errcode= 2
  28212.         goto Failure
  28213.     end
  28214.  
  28215.     commit tran
  28216.     return 1 -- in sp_MSdelsubrows, 1=okay
  28217.  
  28218. Failure:
  28219.     rollback tran sp_MSdelsubrows
  28220.     commit tran
  28221.     return(@errcode) -- in sp_MSdelsubrows, 0=error
  28222.  
  28223. go
  28224. exec dbo.sp_MS_marksystemobject sp_MSdelsubrows 
  28225. go
  28226. grant exec on dbo.sp_MSdelsubrows to public
  28227. go
  28228.  
  28229. raiserror('Creating procedure sp_MSdelsubrowsbatch', 0,1)
  28230. GO
  28231. create PROCEDURE sp_MSdelsubrowsbatch 
  28232.     (@tablenick int,
  28233.      @rowguid_array varbinary(8000),
  28234.      @metadatatype_array varbinary(500), /* 0 - Missing, 1 - Tombstone, 2 - Contents, 3 - ContentsDeferred, 6 - system delete */
  28235.      @oldlineage_len_array varbinary(1000),        -- -- specifies the number of lineages in the @oldlineage_array.
  28236.      @oldlineage_array image,
  28237.      @generation_array varbinary(2000),
  28238.      @newlineage_len_array varbinary(1000),        -- specifies the number of lineages in the @newlineage_array.
  28239.      @newlineage_array image,
  28240.      @pubid uniqueidentifier = NULL,
  28241.      @rowsdeleted INT = NULL OUTPUT)
  28242.  
  28243. as
  28244.     declare @rowguid uniqueidentifier, @metadata_type tinyint, @lineage_old varbinary(255),    
  28245.             @generation int, @lineage_new varbinary(255), @match int, @errcode int, @new_metatype tinyint, 
  28246.             @retcode smallint, @reason nvarchar(255), @procname sysname, @tnstr nvarchar(11), @error int, @rowcount int,
  28247.             @tablenicklast int, @rowguidarraylen int, @oldlineage_len smallint, @newlineage_len smallint,
  28248.             @guidoffset int, @metatypeoffset int, @oldlinlenoffset int, @newlinlenoffset int, @oldlinoffset int,
  28249.             @newlinoffset int, @genoffset int, @transaction_started bit
  28250.             
  28251.     declare @rowstochangetype TABLE (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL)
  28252.  
  28253.     -- Do all DDL first
  28254.     create table #notbelong (    tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, flag int NOT NULL, generation int NULL, 
  28255.                                 lineage_old varbinary(255) NULL, metadatatype_old tinyint NULL, 
  28256.                                 lineage_new varbinary(255) NULL, metadatatype_new tinyint NULL, original_row bit NULL default 0)
  28257.     create index #indnbelong on #notbelong (tablenick, rowguid)
  28258.                 
  28259.     /*
  28260.     ** Check to see if current publication has permission. Skip check if caller is the merge agent.
  28261.     */
  28262.     if @pubid is NULL
  28263.     begin
  28264.         exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick = @tablenick
  28265.         if @retcode<>0 or @@ERROR<>0 return (0)
  28266.     end
  28267.     else
  28268.     begin
  28269.         if ({ fn ISPALUSER(@pubid) } <> 1)
  28270.         begin    
  28271.             RAISERROR (14126, 11, -1)
  28272.             return (1)
  28273.         end
  28274.     end
  28275.         
  28276.     /* Parameter validation */
  28277.     if (@rowguid_array is null)
  28278.     begin
  28279.         RAISERROR(14043, 16, -1, '@rowguid_array')
  28280.         return (0)
  28281.     end
  28282.     if (@tablenick is null)
  28283.     begin
  28284.         RAISERROR(14043, 16, -1, '@tablenick_array')
  28285.         return (0)
  28286.     end
  28287.     if (@newlineage_array is null)
  28288.     begin
  28289.         RAISERROR(14043, 16, -1, '@newlineage_array')
  28290.         return (0)
  28291.     end
  28292.  
  28293.     set    @rowsdeleted = 0
  28294.     set @transaction_started = 0
  28295.  
  28296.     -- initialize offsets and length for walking through arrays
  28297.     set @guidoffset = 1
  28298.     set @metatypeoffset = 1
  28299.     set @oldlinlenoffset = 1
  28300.     set @newlinlenoffset = 1
  28301.     set @oldlinoffset = 1
  28302.     set @newlinoffset = 1
  28303.     set @genoffset = 1
  28304.     
  28305.     set @rowguidarraylen = datalength(@rowguid_array)
  28306.  
  28307.     -- walk through arrays and populate temp table
  28308.     while (@guidoffset < @rowguidarraylen)
  28309.     begin
  28310.         set @rowguid = substring(@rowguid_array, @guidoffset, 16)    -- 16 = sizeof uniqueidentifier (rowguid)
  28311.         set @metadata_type = substring(@metadatatype_array, @metatypeoffset, 1)    -- 1 = sizeof tinyint (metadata_type)
  28312.         set @generation = substring(@generation_array, @genoffset, 4) -- 4 = sizeof int (generation)
  28313.         set @oldlineage_len = substring(@oldlineage_len_array, @oldlinlenoffset, 2) -- 2 = sizeof smallint (oldlineage_len)
  28314.         set @newlineage_len = substring(@newlineage_len_array, @newlinlenoffset, 2) -- 2 = sizeof smallint (newlineage_len)
  28315.         set @lineage_old = substring(@oldlineage_array, @oldlinoffset, @oldlineage_len) -- @oldlineage_len = sizeof old lineage for current row
  28316.         set @lineage_new = substring(@newlineage_array, @newlinoffset, @newlineage_len) -- @newlineage_len = sizeof new lineage for current row
  28317.  
  28318.         -- increment offsets for next row
  28319.         set @guidoffset = @guidoffset + 16
  28320.         set @metatypeoffset = @metatypeoffset + 1
  28321.         set @genoffset = @genoffset + 4
  28322.         set @oldlinlenoffset = @oldlinlenoffset + 2
  28323.         set @newlinlenoffset = @newlinlenoffset + 2
  28324.         set @oldlinoffset = @oldlinoffset + @oldlineage_len
  28325.         set @newlinoffset = @newlinoffset + @newlineage_len
  28326.  
  28327.         -- Insert the old metadata type as the new metadata type. We can modify later if it is supposed to be different.
  28328.         insert into #notbelong (tablenick, rowguid, flag, generation, lineage_old, metadatatype_old, lineage_new, metadatatype_new, original_row) values (@tablenick, @rowguid, 0, @generation, @lineage_old, @metadata_type, @lineage_new, @metadata_type, 1)
  28329.     end
  28330.     
  28331.     if (exists(select * from #notbelong))
  28332.     begin
  28333.         declare @tn int
  28334.         declare @table_name nvarchar(270)
  28335.                     
  28336.         -- Expansion is an expensive and time-consuming process. Defer starting transaction until after expansion 
  28337.         -- has taken place.
  28338.  
  28339.         /* call expand proc */
  28340.         exec @retcode = dbo.sp_MSexpandsubsnb @pubid
  28341.         IF @@ERROR<>0 or @retcode<>0
  28342.         begin
  28343.             set @errcode= 0
  28344.             goto Failure
  28345.         end
  28346.  
  28347.         select @procname = select_proc from sysmergearticles where nickname = @tablenick and pubid = @pubid
  28348.  
  28349.         -- After the #notbelong has been expanded, the original_row column can be used to distinguish original rows
  28350.         -- from the rows that were brought in by the expansion.
  28351.  
  28352.         -- open a cursor on #notbelong for rows with original_row = 1
  28353.         declare original_rows_1 CURSOR LOCAL FAST_FORWARD for 
  28354.         select rowguid, generation, lineage_old, metadatatype_old, lineage_new from #notbelong where tablenick = @tablenick and original_row = 1
  28355.         FOR READ ONLY
  28356.         open original_rows_1
  28357.         fetch original_rows_1 into @rowguid, @generation, @lineage_old, @metadata_type, @lineage_new
  28358.  
  28359.         begin transaction
  28360.         save tran start_of_batch
  28361.         set @transaction_started = 1
  28362.  
  28363.         while (@@fetch_status <> -1)
  28364.         begin
  28365.             
  28366.             -- Are we just changing the type of a tombstone?
  28367.             if (@metadata_type = 5 or @metadata_type = 1)
  28368.             begin
  28369.                 if exists (select * from dbo.MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)
  28370.                 begin
  28371.                     if (@metadata_type = 5)
  28372.                         set @reason = formatmessage (20563) -- Remove from partial
  28373.                     else if (@metadata_type = 1)
  28374.                         set @reason = formatmessage (20562) -- User delete
  28375.  
  28376.                     update dbo.MSmerge_tombstone 
  28377.                         set type = @metadata_type, reason = @reason, generation = @generation, lineage = @lineage_new 
  28378.                         where rowguid = @rowguid and tablenick = @tablenick
  28379.  
  28380.     
  28381.                     -- This row will later be removed from #notbelong. We were only supposed to update the tombstone
  28382.                     -- metadata type for this row (which we have already done above).
  28383.                     insert into @rowstochangetype values (@tablenick, @rowguid)
  28384.                     fetch original_rows_1 into @rowguid, @generation, @lineage_old, @metadata_type, @lineage_new
  28385.                     continue    -- on to the next row
  28386.                 end
  28387.             end
  28388.         
  28389.             -- Are we just changing the type of a tombstone?
  28390.             else if (@metadata_type = 6)
  28391.             begin
  28392.                 if exists (select * from dbo.MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)
  28393.                 begin
  28394.                     set @reason = formatmessage (20564) -- System deleted
  28395.                     update dbo.MSmerge_tombstone set type = @metadata_type, reason = @reason 
  28396.                         where rowguid = @rowguid and tablenick = @tablenick
  28397.  
  28398.     
  28399.                     -- This row will later be removed from #notbelong. We were only supposed to update the tombstone
  28400.                     -- metadata type for this row (which we have already done above).
  28401.                     insert into @rowstochangetype values (@tablenick, @rowguid)
  28402.                     fetch original_rows_1 into @rowguid, @generation, @lineage_old, @metadata_type, @lineage_new
  28403.                     continue    -- on to the next row
  28404.                 end
  28405.             end
  28406.  
  28407.             -- lock this particular row of the base table
  28408.             exec @retcode = @procname @type = 8, @rowguid=@rowguid
  28409.             IF @@ERROR<>0 or @retcode<>0
  28410.             begin
  28411.                 set @errcode= 0
  28412.                 close original_rows_1
  28413.                 deallocate original_rows_1
  28414.                 goto Failure
  28415.             end
  28416.             
  28417.             if @metadata_type = 5
  28418.             begin
  28419.                 set @match = 1
  28420.                 set @new_metatype = 5
  28421.             end
  28422.             else if @metadata_type = 6
  28423.             begin
  28424.                 set @match = 1
  28425.                 set @new_metatype = 6
  28426.             end
  28427.             else if @metadata_type = 7
  28428.             begin
  28429.                 set @match = 1
  28430.                 set @new_metatype = 7
  28431.             end
  28432.             else
  28433.             begin
  28434.                 exec @retcode=sp_MScheckmetadatamatch @metadata_type, @rowguid, @tablenick, @lineage_old, @match output
  28435.                 IF @@ERROR<>0 or @retcode<>0
  28436.                 begin
  28437.                     set @errcode= 0
  28438.                     close original_rows_1
  28439.                     deallocate original_rows_1
  28440.                     goto Failure
  28441.                 end
  28442.  
  28443.                 set @new_metatype = 1
  28444.             end
  28445.  
  28446.             if (@match = 1)
  28447.             begin
  28448.                 if (@metadata_type <> @new_metatype)
  28449.                 begin
  28450.                     -- we will later need this new metadata type when calling sp_MSsetrowmetadata
  28451.                     update #notbelong set metadatatype_new = @new_metatype where tablenick = @tablenick and rowguid = @rowguid and original_row = 1
  28452.                 end
  28453.             end
  28454.             else
  28455.             begin
  28456.                 set @errcode= 2
  28457.                 close original_rows_1
  28458.                 deallocate original_rows_1
  28459.                 goto Failure
  28460.             end
  28461.  
  28462.             fetch original_rows_1 into @rowguid, @generation, @lineage_old, @metadata_type, @lineage_new
  28463.  
  28464.         end
  28465.  
  28466.         close original_rows_1
  28467.         deallocate original_rows_1
  28468.  
  28469.         -- delete the rows in #notbelong that needn't be deleted. We were only supposed to update the tombstone
  28470.         -- metadata type for those rows (which we have already done above).
  28471.         delete #notbelong with (paglock) from #notbelong a, @rowstochangetype b where a.tablenick = b.tablenick and a.rowguid = b.rowguid
  28472.         
  28473.         select @tn = max(tablenick) from #notbelong where flag > -1
  28474.         while @tn is not null
  28475.         begin
  28476.             select @tnstr = convert(nvarchar(11), @tn)
  28477.             exec @retcode = dbo.sp_MStablenamefromnick @tn, @table_name out, @pubid
  28478.             -- delete all rows indicated by the temp table
  28479.             IF @@ERROR<>0 or @retcode<>0
  28480.             begin
  28481.                 set @errcode= 0
  28482.                 goto Failure
  28483.             end
  28484.             exec ('delete from ' + @table_name + ' where RowGuidCol in 
  28485.                 (select rowguid from #notbelong where tablenick = ' + @tnstr + ')' )
  28486.             select @error=@@error, @rowcount=@@rowcount
  28487.             IF @error<>0
  28488.             begin
  28489.                 set @errcode= 0
  28490.                 goto Failure
  28491.             end
  28492.  
  28493.             select @rowsdeleted = @rowsdeleted + @rowcount
  28494.                 
  28495.             -- move on to next nickname - decreasing makes delete order correct
  28496.             update #notbelong set flag = -1 where tablenick = @tn
  28497.             select @tn = max(tablenick) from #notbelong where flag > -1
  28498.         end
  28499.  
  28500.         set @reason = formatmessage (20563) -- Moved out of partial range
  28501.  
  28502.         -- change tombstone type for the non-original rows (the rows that got deleted via expansion).
  28503.         update dbo.MSmerge_tombstone 
  28504.         set type = 5, reason = @reason 
  28505.         from #notbelong nb, dbo.MSmerge_tombstone ts
  28506.         where ts.tablenick = nb.tablenick and
  28507.         ts.rowguid = nb.rowguid
  28508.         and nb.original_row <> 1
  28509.  
  28510.         -- open a cursor and get the new metadata types for the original rows and then call sp_MSsetrowmetadata for each original row.
  28511.         declare original_rows_2 CURSOR LOCAL FAST_FORWARD for 
  28512.         select tablenick, rowguid, generation, lineage_new, metadatatype_new from #notbelong where original_row = 1
  28513.         FOR READ ONLY
  28514.         open original_rows_2
  28515.         fetch original_rows_2 into @tablenick, @rowguid, @generation, @lineage_new, @new_metatype
  28516.         while (@@fetch_status <> -1)
  28517.         begin
  28518.             -- Call sp_MSsetrowmetadata for only the original rows whose delete requests were passed in to this proc.
  28519.             exec @retcode= dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, NULL, @new_metatype, @pubid
  28520.             IF @@ERROR<>0 or @retcode<>0
  28521.             begin
  28522.                 set @errcode= 0
  28523.                 close original_rows_2
  28524.                 deallocate original_rows_2
  28525.                 goto Failure
  28526.             end
  28527.             fetch original_rows_2 into @tablenick, @rowguid, @generation, @lineage_new, @new_metatype
  28528.         end
  28529.         close original_rows_2
  28530.         deallocate original_rows_2
  28531.  
  28532.         commit tran
  28533.  
  28534.     end
  28535.  
  28536.  
  28537.     drop table #notbelong
  28538.     return 1 -- in sp_MSdelsubrows, 1=okay
  28539.  
  28540. Failure:
  28541.  
  28542.     -- instead of checking @@trancount, check our bit flag. This is safer as we can rely on it whether or not we are called 
  28543.     -- from an outer transaction.
  28544.     if (@transaction_started = 1)
  28545.     begin
  28546.         rollback tran start_of_batch
  28547.         commit tran
  28548.     end
  28549.  
  28550.  
  28551.     drop table #notbelong
  28552.  
  28553.     if @errcode = 1
  28554.         set @errcode = 0
  28555.  
  28556.     return(@errcode) -- in sp_MSdelsubrows, 0=error
  28557.  
  28558. go
  28559. exec dbo.sp_MS_marksystemobject sp_MSdelsubrowsbatch 
  28560. go
  28561. grant exec on dbo.sp_MSdelsubrowsbatch to public
  28562. go
  28563.  
  28564. raiserror('Creating procedure sp_MSscriptviewproc', 0,1)
  28565. go
  28566. create procedure dbo.sp_MSscriptviewproc (
  28567.     @viewname  sysname,
  28568.     @ownername sysname,
  28569.     @procname  nvarchar(290),
  28570.     @rgcol     sysname,
  28571.     @objid     int = NULL -- for possible backward comp. issue
  28572.     )
  28573. as
  28574. begin
  28575.  
  28576.     declare @retcode        smallint
  28577.     declare @colname        nvarchar(258)
  28578.     declare @view_id        int
  28579.     declare @iscomputed     tinyint
  28580.     declare @xtype          sysname
  28581.     select @retcode=0
  28582.  
  28583.     -- security check
  28584.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @objid=@objid
  28585.     if @@error <> 0 or @retcode <> 0
  28586.         return 1
  28587.  
  28588.     declare @proctext       table (line_no int primary key identity(1,1), line nvarchar(4000))
  28589.     if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Failure end 
  28590.  
  28591.     set nocount on
  28592.     select @procname=QUOTENAME(@procname)
  28593.     insert into @proctext (line) values (
  28594. 'create procedure dbo.' + @procname + ' (@tablenick int, @max_rows int = NULL,
  28595.     @guidlast uniqueidentifier = ''00000000-0000-0000-0000-000000000000'') 
  28596.     AS
  28597.     
  28598.     set nocount on
  28599.     set rowcount 0
  28600.  
  28601.     declare @retcode int
  28602.  
  28603.     -- security check
  28604.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick=@tablenick
  28605.     if @@error <> 0 or @retcode <> 0
  28606.         return 1
  28607.  
  28608.     if  @max_rows is not null
  28609.     begin
  28610.         -- used to select data for initial pop. of subscriber for dynamic filtered publication
  28611.         declare @lin varbinary (255)
  28612.         declare @cv varbinary (2048)
  28613.         declare @replnick int
  28614.         declare @objid int
  28615.         declare @ccols int
  28616.         declare @command nvarchar(4000)
  28617.         
  28618.         select @objid = objid from sysmergearticles where nickname = @tablenick
  28619.         select @ccols = max(colid) from syscolumns where id = @objid
  28620.         
  28621.         exec dbo.sp_MSgetreplnick @nickname = @replnick out
  28622.         if (@@error <> 0) or @replnick IS NULL 
  28623.         begin
  28624.             RAISERROR (14055, 11, -1)
  28625.             RETURN(1)
  28626.         end                 
  28627.         set @lin = { fn UPDATELINEAGE(0x0, @replnick, 1) }
  28628.         set @cv = { fn INITCOLVS(@ccols, @replnick) }
  28629.  
  28630.         if @max_rows <> 0
  28631.         begin
  28632.             set rowcount @max_rows
  28633.             select @tablenick, v.' + @rgcol + ', coalesce (c.generation,1), 
  28634.                 coalesce (c.lineage, @lin), coalesce (c.colv1, @cv)')
  28635.     if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Failure end 
  28636.  
  28637.     if @objid is not NULL and exists (select * from syscolumns where id = @objid 
  28638.         and (iscomputed=1 or type_name(xtype)='timestamp'))
  28639.     begin
  28640.         select @view_id = object_id(@viewname)
  28641.         declare collist1 cursor local fast_forward for 
  28642.             select name from syscolumns where id = @view_id order by colid asc
  28643.                 for read only
  28644.         open collist1
  28645.         fetch collist1 into @colname
  28646.         while (@@fetch_status <> -1)
  28647.         begin
  28648.             --since a view does not preserve computed/timestamp property, we have to rely on the base table
  28649.             select @iscomputed=iscomputed, @xtype=xtype from syscolumns where id = @objid and name=@colname
  28650.             if @iscomputed=0 and type_name(@xtype) <> 'timestamp'
  28651.             begin
  28652.                 select @colname = QUOTENAME(@colname) --previously we use rowguidcol to replace 'rowguid'
  28653.                                                       --which can cause problems and is not necessary.
  28654.                 insert @proctext (line) values('
  28655.             , v.' + @colname) 
  28656.                 if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Failure end 
  28657.             end
  28658.             fetch next from collist1 into @colname
  28659.         end                 
  28660.     end
  28661.     else
  28662.     begin
  28663.         insert into @proctext (line) values (
  28664. '             , v.*')
  28665.         if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Failure end 
  28666.     end
  28667.  
  28668.     insert into @proctext (line) values ('
  28669.             from ' +
  28670.                  QUOTENAME(@ownername) + '.' +
  28671.                     QUOTENAME(@viewname) + ' v left outer join  dbo.MSmerge_contents c on
  28672.                       v.' + @rgcol + ' = c.rowguid  and c.tablenick = @tablenick where v.' + @rgcol + ' > @guidlast 
  28673.                      order by v.' + @rgcol + '
  28674.         end
  28675.         else
  28676.         begin
  28677.             select @tablenick, v.' + @rgcol + ', coalesce (c.generation,1), 
  28678.                 coalesce (c.lineage, @lin), coalesce (c.colv1, @cv)')
  28679.     
  28680.     if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Failure end 
  28681.         
  28682.     if @objid is not NULL and exists (select * from syscolumns where id = @objid 
  28683.         and (iscomputed=1 or type_name(xtype)='timestamp'))
  28684.     begin
  28685.         select @view_id = object_id(@viewname)
  28686.         declare collist2 cursor local fast_forward for 
  28687.             select name from syscolumns where id = @view_id order by colid asc
  28688.                 for read only
  28689.         open collist2
  28690.         fetch collist2 into @colname
  28691.         while (@@fetch_status <> -1)
  28692.         begin
  28693.             --since a view does not preserve computed/timestamp property, we have to rely on the base table
  28694.             select @iscomputed=iscomputed, @xtype=xtype from syscolumns where id = @objid and name=@colname
  28695.             if @iscomputed=0 and type_name(@xtype) <> 'timestamp'
  28696.             begin
  28697.                 select @colname = QUOTENAME(@colname) --previously we use rowguidcol to replace 'rowguid'
  28698.                                                       --which can cause problems and is not necessary.
  28699.                 insert @proctext (line) values('
  28700.             , v.' + @colname) 
  28701.                 if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Failure end 
  28702.             end
  28703.             fetch next from collist2 into @colname
  28704.         end                 
  28705.     end
  28706.     else
  28707.     begin
  28708.         insert into @proctext (line) values (
  28709. '             , v.*')
  28710.         if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Failure end 
  28711.     end
  28712.  
  28713.     insert into @proctext (line) values ('
  28714.             from ' +
  28715.                  QUOTENAME(@ownername) + '.' +
  28716.                     QUOTENAME(@viewname) + ' v left outer join  dbo.MSmerge_contents c on
  28717.                       v.' + @rgcol + ' = c.rowguid  and c.tablenick = @tablenick
  28718.                      order by v.' + @rgcol + '
  28719.         end
  28720.     
  28721.         return (1)      
  28722.     end ')
  28723.  
  28724.     insert into @proctext (line) values ('
  28725.     select @command = N''insert into #belong (tablenick, rowguid, flag, skipexpand, partchangegen, joinchangegen)
  28726.         select ct.tablenick, ct.rowguid, 0, 0, ct.partchangegen, ct.joinchangegen
  28727.                     from  #contents_subset ct, ' + QUOTENAME(@ownername) + '.' +
  28728.                     QUOTENAME(@viewname) + ' v where ct.tablenick = @tablenick
  28729.                     and ct.rowguid = v.' + @rgcol + '''  
  28730.     
  28731.     exec @retcode = sp_executesql @command, N''@tablenick int'', @tablenick = @tablenick
  28732.     if @@error <> 0 or @retcode <> 0 return 1
  28733.         
  28734.     if @@ERROR <> 0
  28735.         begin
  28736.         RAISERROR(''Error selecting from view'' , 16, -1)
  28737.         return (1)  
  28738.         end')
  28739.             
  28740.     select line from @proctext order by line_no asc
  28741. Failure:
  28742.     return @retcode
  28743. end
  28744. go
  28745. exec dbo.sp_MS_marksystemobject sp_MSscriptviewproc
  28746. go
  28747. grant execute on sp_MSscriptviewproc to public
  28748. go
  28749. raiserror('Creating procedure sp_MSmakeviewproc', 0,1)
  28750. GO
  28751.  
  28752. create procedure sp_MSmakeviewproc (
  28753.     @viewname sysname,
  28754.     @ownername sysname,
  28755.     @procname nvarchar(290),
  28756.     @rgcol sysname,
  28757.     @objid int = NULL --for possible backward comp. issue
  28758.     )
  28759. as
  28760. begin
  28761.     declare @retcode        smallint
  28762.     declare @command        nvarchar(4000)
  28763.     declare @db_name        sysname
  28764.     set nocount on
  28765.  
  28766.     select @retcode = 0
  28767.     select @db_name = db_name()
  28768.     if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Failure end 
  28769.  
  28770.     select @command = N'exec dbo.sp_MSscriptviewproc 
  28771.         @viewname = ' + fn_replmakestringliteral(@viewname) collate database_default + '
  28772.         ,@ownername = ' + fn_replmakestringliteral(@ownername) collate database_default + '
  28773.         ,@procname = ' + fn_replmakestringliteral(@procname) collate database_default + '
  28774.         ,@rgcol = ' + fn_replmakestringliteral(@rgcol) collate database_default + '
  28775.         ,@objid = ' + isnull(convert(nvarchar(20), @objid), N'null') 
  28776.     if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Failure end 
  28777.  
  28778.     exec @retcode = master.dbo.xp_execresultset @command, @db_name
  28779.     if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Failure end 
  28780.  
  28781.     select @procname=QUOTENAME(@procname)
  28782.     exec dbo.sp_MS_marksystemobject @procname
  28783.     if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Failure end 
  28784.     exec ('grant exec on ' + @procname + ' to public')
  28785.     if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Failure end 
  28786.  
  28787. Failure:
  28788.     return @retcode
  28789. end
  28790. go
  28791. exec dbo.sp_MS_marksystemobject sp_MSmakeviewproc 
  28792. go
  28793. create procedure sp_MScreatebeforetable
  28794.     @objid int
  28795. AS
  28796.     declare     @command            nvarchar(4000)
  28797.     declare     @objidstr            nvarchar(12)
  28798.     declare     @dbname             sysname
  28799.     declare        @oldname            sysname
  28800.     declare     @newname             sysname
  28801.     declare     @nameguid             uniqueidentifier
  28802.     declare     @before_rowguidname sysname
  28803.     declare     @retcode             int
  28804.      declare     @tablenick                 int
  28805.     set nocount on
  28806.  
  28807.     set @before_rowguidname = NULL
  28808.  
  28809. -- If no publication including this table needs before images, just return
  28810.     if not exists (select * from sysmergepublications p, sysmergearticles a where
  28811.             a.objid = @objid and p.pubid = a.pubid and p.keep_before_values = 1)
  28812.         return (0)
  28813.     select @tablenick = max(nickname) from sysmergearticles where objid = @objid
  28814.     if @tablenick is null return (1)
  28815.  
  28816. -- If a before image table already exists for this table, we need to drop it and create a new one
  28817.     select @oldname = max(o.name) from sysobjects o, sysmergearticles a where
  28818.         a.objid = @objid and o.id = a.before_image_objid
  28819.     if @oldname is not null
  28820.         begin
  28821.            exec @retcode = sp_MShelpalterbeforetable @objid, @oldname
  28822.            if @@error<>0 or @retcode<>0 return (1)
  28823.            return(0)
  28824.         end
  28825. -- If this table is not involved with any filters or join filters, don't bother
  28826.     if not exists (select * from sysmergesubsetfilters where art_nickname = @tablenick
  28827.         or join_nickname = @tablenick) and
  28828.         not exists (select * from sysmergearticles where nickname = @tablenick and
  28829.             datalength (subset_filterclause) > 1)
  28830.         return(0)
  28831.     
  28832. -- Generate a unique name for our new table
  28833.     set @nameguid = newid()
  28834.     exec @retcode = dbo.sp_MSguidtostr @nameguid, @newname out
  28835.     if @@ERROR <>0 OR @retcode <>0 return (1)
  28836.     set @newname = 'MS_bi' + @newname
  28837.  
  28838. -- Call xp_execresultset with helper function command
  28839.     set @objidstr = convert(nvarchar(12), @objid)
  28840.     set @dbname = db_name()
  28841.  
  28842.        set @command = 'exec dbo.sp_MShelpcreatebeforetable '  + @objidstr + ', ''' + @newname + '''' 
  28843.        exec @retcode = master..xp_execresultset @command, @dbname
  28844.        if @@error<>0 or @retcode<>0 return (1)
  28845.  
  28846.     select @before_rowguidname=quotename(name) from syscolumns where id=@objid and columnproperty(@objid, name , 'isrowguidcol')=1
  28847.  
  28848.     if @before_rowguidname is not NULL
  28849.         begin
  28850.                exec ('grant select (' + @before_rowguidname + ') on ' + @newname + ' to public')
  28851.                if @@ERROR<>0 return (1)
  28852.         end
  28853.  
  28854.     /* grant select to system_delete column */
  28855.     -- grant only to the PAL role instead of to public
  28856.     declare @role sysname
  28857.     declare @pubid uniqueidentifier
  28858.     declare publications_list CURSOR LOCAL FAST_FORWARD 
  28859.         for select p.pubid from dbo.sysmergearticles a, dbo.sysmergepublications p 
  28860.             where objid = @objid and p.pubid = a.pubid and UPPER(p.publisher) = UPPER(@@servername) collate database_default and p.publisher_db = db_name()
  28861.  
  28862.     open publications_list
  28863.     fetch publications_list into @pubid
  28864.     while @@fetch_status <> -1
  28865.     begin
  28866.         exec @retcode = dbo.sp_MSrepl_FixPALRole @pubid, @role output
  28867.         if @retcode <> 0 or @@ERROR<>0 
  28868.             return (1)
  28869.         
  28870.            exec ('grant select (system_delete, generation), update(generation), delete on ' + @newname + ' to ' + @role)
  28871.            if @@ERROR<>0 return (1)
  28872.            
  28873.         fetch publications_list into @pubid
  28874.     end
  28875.     close publications_list
  28876.     deallocate publications_list
  28877.  
  28878.        exec dbo.sp_MS_marksystemobject @newname
  28879.     if @@ERROR<>0 return (1)
  28880.  
  28881.     update sysmergearticles set before_image_objid = object_id( @newname )
  28882.         where objid = @objid
  28883.  
  28884.     return(0)
  28885. go
  28886. exec dbo.sp_MS_marksystemobject sp_MScreatebeforetable 
  28887. go
  28888.  
  28889. create procedure sp_MShelpcreatebeforetable
  28890.     @objid int,
  28891.     @newname sysname
  28892. AS
  28893.     declare @command nvarchar(1000)
  28894.     declare @retcode int
  28895.     declare @include int
  28896.     declare @tablenick int
  28897.     declare @colpat nvarchar(130)
  28898.     declare @colname nvarchar(140)
  28899.     declare @typename nvarchar(140)
  28900.     declare @colid smallint
  28901.     declare @colidstr nvarchar(3)
  28902.     declare @status tinyint
  28903.     declare @len smallint
  28904.     declare @prec smallint
  28905.     declare @scale int
  28906.     declare @isnullable tinyint
  28907.     declare @cMaxIndexLength int
  28908.  
  28909.     set @cMaxIndexLength= 900  -- max index column size in SQL 2000
  28910.  
  28911.     set nocount on
  28912.  
  28913.     -- Security check
  28914.     if 1 <> is_member('db_owner')
  28915.     begin
  28916.         RAISERROR (15247, 11, -1)
  28917.         return 1
  28918.     end
  28919.  
  28920.     select @tablenick = max(nickname) from sysmergearticles where objid = @objid
  28921.     if @tablenick is null 
  28922.     begin
  28923.         select 'a' = 'raiserror (''Error creating before image table'' , 16, -1)'
  28924.         return (1)
  28925.     end
  28926.         
  28927.     -- create temp table to select the command text out of
  28928.     create table #tempcmd (phase int NOT NULL, step int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)
  28929.  
  28930.     set @command = 'create table dbo.' + quotename(@newname) + '('
  28931.     insert into #tempcmd (phase, cmdtext) values (1, @command)
  28932.     
  28933.     -- Loop over the columns and see which ones we include
  28934.     declare col_cursor CURSOR LOCAL FAST_FORWARD for select name, status, type_name(xtype), length,
  28935.          prec, scale, isnullable, colid from syscolumns
  28936.     where id = @objid and iscomputed <> 1 and type_name(xtype) <> 'timestamp' order by colid
  28937.     FOR READ ONLY
  28938.     
  28939.     open col_cursor
  28940.     fetch next from col_cursor into @colname, @status, @typename, @len, @prec, @scale, @isnullable, @colid
  28941.     while (@@fetch_status <> -1)
  28942.     begin
  28943.         set @include = 0
  28944.         set @colpat = '%' + @colname + '%'
  28945.         if columnproperty( @objid, @colname , 'isrowguidcol')=1
  28946.         begin
  28947.             set @include = 1
  28948.         end
  28949.         else
  28950.         begin
  28951.             -- does updating this column change membership in a partial replica? 
  28952.             if exists (select * from sysmergearticles 
  28953.                 where objid = @objid and subset_filterclause like @colpat)
  28954.                 set @include = 1
  28955.             else if exists (select * from sysmergesubsetfilters
  28956.                 where art_nickname = @tablenick and join_filterclause like @colpat)
  28957.                 set @include = 1
  28958.             else if exists (select * from sysmergesubsetfilters
  28959.                  where join_nickname = @tablenick and join_filterclause like @colpat)
  28960.                 set @include = 1
  28961.         end
  28962.         -- If we want this column, map its type and insert a row to temp table
  28963.         if @include = 1
  28964.         begin
  28965.             if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
  28966.                 set @len = @len/2
  28967.             exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale            
  28968.             if @@ERROR<>0 or @retcode<>0 goto Failure
  28969.             if @typename not in ('text', 'ntext','image')
  28970.             begin
  28971.                 select @colname = N'[' + replace(@colname, N']', N']]') + N']'
  28972.     
  28973.                 if @isnullable = 1
  28974.                     set @command = @colname + ' ' + @typename + ' NULL, '
  28975.                 else
  28976.                     set @command = @colname + ' ' + @typename + ' NOT NULL, '
  28977.                 
  28978.                 -- Insert the part of create table command for this column
  28979.                 insert into #tempcmd (phase, cmdtext) values (1, @command)
  28980.  
  28981.                 -- Insert a create index command if column is not too long
  28982.                 if (@len <= @cMaxIndexLength)
  28983.                 begin
  28984.                     set @colidstr =convert(nvarchar(3), @colid)
  28985.                     set @command = 'create index ' + quotename(@newname + '_' + @colidstr) + ' on ' + quotename(@newname) + ' (' + @colname + ') '
  28986.                     insert into #tempcmd (phase, cmdtext) values (2, @command)
  28987.                 end
  28988.             end
  28989.         end
  28990.         /* Repeat the loop with next column */
  28991.         fetch next from col_cursor into @colname, @status, @typename, @len, @prec, @scale, @isnullable, @colid
  28992.     end
  28993.  
  28994.     close col_cursor
  28995.     deallocate col_cursor
  28996.  
  28997.     -- Insert last column, generation
  28998.     set @command = 'generation int NOT NULL, system_delete bit default(0))
  28999.         '
  29000.     insert into #tempcmd (phase, cmdtext) values (1, @command)
  29001.     set @command = 'create clustered index ' + quotename(@newname + '_gen') + ' on ' + quotename(@newname) + '(generation) 
  29002.         '
  29003.     insert into #tempcmd (phase, cmdtext) values (2, @command)
  29004.         
  29005.     select cmdtext from #tempcmd order by phase, step
  29006.     drop table #tempcmd
  29007.  
  29008.     return(0)
  29009. Failure:
  29010.     close col_cursor
  29011.     deallocate col_cursor
  29012.     return(1)
  29013. go
  29014. exec dbo.sp_MS_marksystemobject sp_MShelpcreatebeforetable 
  29015. go
  29016. grant execute on dbo.sp_MShelpcreatebeforetable to public
  29017. go
  29018. create procedure sp_MShelpalterbeforetable
  29019.     @objid int,
  29020.     @biname sysname
  29021. AS
  29022.     declare @command nvarchar(4000)
  29023.     declare @retcode int
  29024.     declare @include int
  29025.     declare @tablenick int
  29026.     declare @colpat nvarchar(130)
  29027.     declare @colname nvarchar(130)
  29028.     declare @typename sysname
  29029.     declare @colid smallint
  29030.     declare @colidstr nvarchar(3)
  29031.     declare @status tinyint
  29032.     declare @len smallint
  29033.     declare @prec smallint
  29034.     declare @scale int
  29035.     declare @isnullable tinyint
  29036.     declare @bi_objid int
  29037.     set nocount on
  29038.     declare @cMaxIndexLength int
  29039.  
  29040.     set @cMaxIndexLength= 900  -- max index column size in SQL 2000
  29041.  
  29042.     select @tablenick = max(nickname) from sysmergearticles where objid = @objid
  29043.     if @tablenick is null 
  29044.         return (1)
  29045.  
  29046.     select @bi_objid = OBJECT_ID(@biname)        
  29047.     
  29048.     -- Loop over the columns and see which ones we include
  29049.     declare col_cursor CURSOR LOCAL FAST_FORWARD for select name, status, type_name(xtype), length,
  29050.          prec, scale, isnullable, colid from syscolumns
  29051.     where id = @objid and iscomputed <> 1 and type_name(xtype) <> 'timestamp' order by colid
  29052.     FOR READ ONLY
  29053.     
  29054.     open col_cursor
  29055.     fetch next from col_cursor into @colname, @status, @typename, @len, @prec, @scale, @isnullable, @colid
  29056.     while (@@fetch_status <> -1)
  29057.         begin
  29058.         set @include = 0
  29059.         set @colpat = '%' + @colname + '%'
  29060.  
  29061.         if not exists (select * from syscolumns where id = @bi_objid and QUOTENAME(name) = QUOTENAME('system_delete'))
  29062.             begin
  29063.                 set @command = 'alter table ' + @biname + ' ADD system_delete bit default(0) '
  29064.                 execute ( @command )
  29065.                 if @@ERROR<>0 
  29066.                     goto errlabel
  29067.  
  29068.                 /* grant select to system_delete column */
  29069.                    exec ('grant select (system_delete) on ' + @biname + ' to public')
  29070.                    if @@ERROR<>0 
  29071.                     goto errlabel
  29072.  
  29073.                     
  29074.             end
  29075.  
  29076.         --should not grant select to public. Instead grant to the publication PAL role
  29077.         -- grant only to the PAL role instead of to public
  29078.         declare @role sysname
  29079.         declare @pubid uniqueidentifier
  29080.         declare publications_list CURSOR LOCAL FAST_FORWARD 
  29081.             for select p.pubid from dbo.sysmergearticles a, dbo.sysmergepublications p 
  29082.             where objid = @objid and p.pubid = a.pubid and UPPER(p.publisher) = UPPER(@@servername) collate database_default and p.publisher_db = db_name()
  29083.  
  29084.         open publications_list
  29085.         fetch publications_list into @pubid
  29086.         while @@fetch_status <> -1
  29087.         begin
  29088.             exec @retcode = dbo.sp_MSrepl_FixPALRole @pubid, @role output
  29089.             if @retcode <> 0 or @@ERROR<>0 
  29090.                 return (1)
  29091.             
  29092.                exec ('grant select (generation), update(generation), delete on ' + @biname + ' to ' + @role)
  29093.                if @@ERROR<>0 return (1)
  29094.                
  29095.             fetch publications_list into @pubid
  29096.         end
  29097.         close publications_list
  29098.         deallocate publications_list
  29099.  
  29100.         
  29101.         /*exec ('grant select (generation), update(generation), delete on ' + @biname + ' to public')
  29102.                    if @@ERROR<>0 
  29103.                     goto errlabel*/
  29104.  
  29105.         -- Is this column already in the before image table?
  29106.         -- or the column is not in the vertical partitioning?
  29107.         if exists (select * from syscolumns where id = @bi_objid and name = @colname) OR
  29108.             exists (select * from sysmergearticles where objid=@objid and not exists (
  29109.                 select * from syscolumns where id = sync_objid and name = @colname))
  29110.             begin
  29111.             goto fetchnext
  29112.             end
  29113.  
  29114.         -- does updating this column change membership in a partial replica? 
  29115.         if exists (select * from sysmergearticles 
  29116.             where objid = @objid and subset_filterclause like @colpat)
  29117.             set @include = 1
  29118.         else if exists (select * from sysmergesubsetfilters
  29119.             where art_nickname = @tablenick and join_filterclause like @colpat)
  29120.             set @include = 1
  29121.         else if exists (select * from sysmergesubsetfilters
  29122.             where join_nickname = @tablenick and join_filterclause like @colpat)
  29123.             set @include = 1
  29124.  
  29125.         -- If we want this column, map its type and insert a row to temp table
  29126.         if @include <> 1
  29127.             begin
  29128.             goto fetchnext
  29129.             end
  29130.         if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
  29131.             set @len = @len/2
  29132.         exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale
  29133.         if @@ERROR<>0 or @retcode<>0 
  29134.             goto errlabel
  29135.         if @typename not in ('text', 'ntext','image')
  29136.         begin
  29137.             set @colname = QUOTENAME(@colname)
  29138.     
  29139.             -- Always make columns nullable when we add them because we might have
  29140.             -- existing rows in the before image table.
  29141.  
  29142.             set @command = 'alter table ' + @biname + ' ADD ' + @colname + ' ' + @typename + ' NULL '
  29143.         
  29144.             execute ( @command )
  29145.             if @@ERROR<>0 goto errlabel
  29146.  
  29147.             -- Insert a create index command if column is not too long
  29148.             if (@len <= @cMaxIndexLength)
  29149.             begin
  29150.                 set @colidstr =convert(nvarchar(3), @colid)
  29151.                  set @command = 'create index ' + @biname + '_' + @colidstr + ' on ' + @biname + ' (' + @colname + ')'
  29152.                 execute ( @command )
  29153.                 if @@ERROR<>0 goto errlabel
  29154.             end
  29155.         end
  29156.                             
  29157. fetchnext:
  29158.         /* Repeat the loop with next column */
  29159.         fetch next from col_cursor into @colname, @status, @typename, @len, @prec, @scale, @isnullable, @colid
  29160.         end
  29161.     close col_cursor
  29162.     deallocate col_cursor    
  29163.     return 0
  29164. errlabel:
  29165.     close col_cursor
  29166.     deallocate col_cursor    
  29167.     return 1
  29168.  
  29169. go
  29170.  
  29171. exec dbo.sp_MS_marksystemobject sp_MShelpalterbeforetable 
  29172. go
  29173.  
  29174. create procedure sp_MSgetbeforetableinsert
  29175.     @objid int,
  29176.     @inscommand nvarchar(2000) output
  29177. AS
  29178.     declare @before_objid int
  29179.     declare @before_name sysname
  29180.     declare @collist nvarchar(1000)
  29181.     declare @colname sysname
  29182.     declare @guidstr nvarchar(36)
  29183.     declare @beforeview sysname
  29184.     declare @retcode int
  29185.     declare @artid uniqueidentifier
  29186.  
  29187.     -- Do we have a before table?
  29188.     select @before_objid = max(before_image_objid) from sysmergearticles where objid = @objid and
  29189.             before_image_objid is not null
  29190.     select @before_name = OBJECT_NAME(@before_objid)
  29191.  
  29192.     if @before_name is null
  29193.     begin
  29194.         set @inscommand = ''
  29195.         return 0
  29196.     end
  29197.     
  29198.     select @artid = artid from sysmergearticles where objid = @objid
  29199.     exec @retcode=sp_MSguidtostr @artid, @guidstr out
  29200.     if @retcode<>0 or @@ERROR<>0 return (1)
  29201.     
  29202.     set @beforeview = 'MSbivw_' + @guidstr
  29203.  
  29204.     set @collist = ''
  29205.     -- Loop over columns to make the column list for the insert / select command
  29206.     declare col_cursor CURSOR LOCAL FAST_FORWARD for select name from syscolumns
  29207.     where id = @before_objid and name <> 'generation' and name <> 'system_delete' order by colid
  29208.     FOR READ ONLY
  29209.  
  29210.     open col_cursor
  29211.  
  29212.     fetch next from col_cursor into @colname
  29213.     while (@@fetch_status <> -1)
  29214.         begin
  29215.         set @collist = @collist + QUOTENAME(@colname) + ', '
  29216.         fetch next from col_cursor into @colname
  29217.         end
  29218.     close col_cursor
  29219.     deallocate col_cursor
  29220.  
  29221.     -- Our list has all of the columns except generation since that gets set to a local variable
  29222.     -- Make the insert command
  29223.     set @inscommand = 'insert into ' + QUOTENAME(@beforeview) + ' ( ' + @collist +
  29224.         ' generation) select ' + @collist + ' a.gen_cur from deleted, (select top 1 nickname, gen_cur = isnull(gen_cur, 0) from dbo.sysmergearticles where nickname = @tablenick) as a '
  29225.  
  29226.     return 0
  29227.     
  29228. go
  29229. exec dbo.sp_MS_marksystemobject sp_MSgetbeforetableinsert 
  29230. go
  29231.  
  29232. create procedure sp_MSfixupbeforeimagetables(@pubid uniqueidentifier)
  29233. AS
  29234. begin
  29235.     -- This procedure updates the generations in the existing rows in the before-image
  29236.     -- tables of all articles in the specified publication to the current gen_cur value for 
  29237.     -- the respective article.
  29238.     -- This is done after the subscription has been reinitialized (at a republisher). The reason
  29239.     -- is that the genhistory rows at the subscriber no longer correspond to the values before 
  29240.     -- the reinit. They are simply bcp-ed in from the bcp generated at the publisher. 
  29241.     -- Setting the existing before image rows to gen_cur has the effect of avoiding the retention-
  29242.     -- based cleanup of these rows based on invalid coldate values (since they are in context of
  29243.     -- the publisher). The cleanup thus gets delayed to when the current gen_cur value expires retention.
  29244.     declare @before_image_tablename sysname, @gencur int, @gencur_str nvarchar(20), @cmd nvarchar(256)
  29245.  
  29246.     if @pubid is null
  29247.         return 0
  29248.  
  29249.     if ({ fn ISPALUSER(@pubid) } <> 1)
  29250.     begin    
  29251.         RAISERROR (14126, 11, -1)
  29252.         return (1)
  29253.     end
  29254.  
  29255.     declare beforeimagetables_cursor CURSOR LOCAL FAST_FORWARD for 
  29256.     select distinct object_name(before_image_objid), gen_cur 
  29257.     from sysmergearticles 
  29258.     where artid in 
  29259.         (select artid from sysmergearticles where pubid = @pubid)
  29260.     and before_image_objid is not null
  29261.     FOR READ ONLY
  29262.  
  29263.     open beforeimagetables_cursor
  29264.     fetch next from beforeimagetables_cursor into @before_image_tablename, @gencur
  29265.  
  29266.     while (@@fetch_status <> -1)
  29267.     begin
  29268.         
  29269.         if @before_image_tablename is not null
  29270.         begin
  29271.             select @gencur_str = convert(nvarchar(20), @gencur)
  29272.             select @cmd = 'update ' + quotename(@before_image_tablename) + ' set generation = ' + @gencur_str
  29273.             exec (@cmd)
  29274.         end
  29275.         
  29276.         fetch next from beforeimagetables_cursor into @before_image_tablename, @gencur
  29277.     end
  29278.  
  29279.     close beforeimagetables_cursor
  29280.     deallocate beforeimagetables_cursor
  29281.  
  29282.     return 0
  29283. end
  29284.  
  29285. go
  29286. exec dbo.sp_MS_marksystemobject sp_MSfixupbeforeimagetables 
  29287. go
  29288. grant exec on dbo.sp_MSfixupbeforeimagetables to public
  29289. go
  29290.  
  29291. create procedure sp_MSreplcheck_permission(
  29292.     @objid int,
  29293.     @type int,
  29294.     @permissions int)
  29295. AS
  29296.     declare @tablename sysname
  29297.     declare @ownername    sysname
  29298.  
  29299.     select @ownername=user_name(uid) from sysobjects where id=@objid
  29300.     select @tablename=object_name(@objid)
  29301.  
  29302.     -- bypass this checking for dbo or member of db_owner.
  29303.     if is_srvrolemember('sysadmin') = 1 or is_member ('db_owner') = 1
  29304.         return (0)
  29305.         
  29306.     if @permissions=0
  29307.         return (0)
  29308.  
  29309.     --insert
  29310.     if @type=1 and @permissions & 1 = 1 and permissions(@objid) & 0x8=0
  29311.         return (1)
  29312.         
  29313.     --update        
  29314.     if @type=2 and @permissions & 2 = 2 and permissions(@objid) & 0x2=0
  29315.         return (1)
  29316.  
  29317.     --delete
  29318.     if @type=3 and @permissions & 4 = 4 and permissions(@objid) & 0x10=0
  29319.         return (1) 
  29320.         
  29321.     return (0)
  29322. GO
  29323. grant exec on sp_MSreplcheck_permission to public
  29324. go
  29325. exec dbo.sp_MS_marksystemobject sp_MSreplcheck_permission
  29326. go
  29327.  
  29328. create procedure sp_MSinserterrorlineage 
  29329.     (@tablenick int, 
  29330.      @rowguid uniqueidentifier,
  29331.      @lineage varbinary(255))
  29332. as
  29333.     declare @retcode int
  29334.     -- security check
  29335.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @tablenick=@tablenick
  29336.     if @@error <> 0 or @retcode <> 0
  29337.         return 1
  29338.  
  29339.     if exists (select * from MSmerge_errorlineage where tablenick = @tablenick and
  29340.                 rowguid = @rowguid)
  29341.             update MSmerge_errorlineage set lineage = @lineage where tablenick = @tablenick and
  29342.                 rowguid = @rowguid
  29343.     else
  29344.             insert into MSmerge_errorlineage (tablenick, rowguid, lineage) 
  29345.                 values (@tablenick, @rowguid, @lineage)
  29346.     if @@ERROR <> 0 return (1)
  29347.  
  29348.     return 0
  29349. go
  29350. grant exec on sp_MSinserterrorlineage to public
  29351. go
  29352. exec dbo.sp_MS_marksystemobject sp_MSinserterrorlineage 
  29353. go
  29354. create procedure sp_MSevalsubscriberinfo 
  29355.     (@pubid uniqueidentifier)
  29356. as
  29357.     
  29358.     declare @expr nvarchar(500)
  29359.  
  29360.     if ({ fn ISPALUSER(@pubid) } <> 1)
  29361.     begin    
  29362.         RAISERROR (14126, 11, -1)
  29363.         return (1)
  29364.     end
  29365.     
  29366.     select @expr = validate_subscriber_info from sysmergepublications  where pubid = @pubid
  29367.     exec ('select ' + @expr)
  29368.     if @@error<>0 return(1)
  29369.     
  29370.     return(0)
  29371. go
  29372.  
  29373. grant exec on sp_MSevalsubscriberinfo to public
  29374. go
  29375. exec dbo.sp_MS_marksystemobject sp_MSevalsubscriberinfo 
  29376. go
  29377.  
  29378. create procedure sp_MSsetsubscriberinfo 
  29379.     (@pubid uniqueidentifier, @expr nvarchar(500))
  29380. as
  29381.     if ({ fn ISPALUSER(@pubid) } <> 1)
  29382.     begin    
  29383.         RAISERROR (14126, 11, -1)
  29384.         return (1)
  29385.     end
  29386.  
  29387.     update sysmergepublications set validate_subscriber_info = @expr where pubid = @pubid
  29388. go
  29389.  
  29390. grant exec on sp_MSsetsubscriberinfo to public
  29391. go
  29392. exec dbo.sp_MS_marksystemobject sp_MSsetsubscriberinfo 
  29393. go
  29394. create procedure sp_MSgetsubscriberinfo 
  29395.     (@pubid uniqueidentifier)
  29396. as
  29397.     declare @expr nvarchar(500)
  29398.     
  29399.     if ({ fn ISPALUSER(@pubid) } <> 1)
  29400.     begin    
  29401.         RAISERROR (14126, 11, -1)
  29402.         return (1)
  29403.     end
  29404.  
  29405.     select @expr = validate_subscriber_info from sysmergepublications  where pubid = @pubid
  29406.     -- Return the value --
  29407.     select @expr
  29408. go
  29409.  
  29410. grant exec on sp_MSgetsubscriberinfo to public
  29411. go
  29412. exec dbo.sp_MS_marksystemobject sp_MSgetsubscriberinfo 
  29413. go
  29414.  
  29415. raiserror('Creating procedure sp_MSmakectsview', 0,1)
  29416. GO
  29417.  
  29418. create procedure sp_MSmakectsview
  29419.     @publication sysname,
  29420.     @ctsview     sysname,
  29421.     @dynamic_snapshot_views_table_name sysname = null
  29422. AS
  29423.     set nocount on
  29424.     declare @pubid          uniqueidentifier
  29425.     declare @artid          uniqueidentifier
  29426.     declare @pubidstr        nvarchar(40)
  29427.     declare @artidstr        nvarchar(40)
  29428.     declare @objid        int
  29429.     declare @tablenick    int
  29430.     declare @new_inactive int
  29431.     declare @new_active int
  29432.     declare @tablenickstr nvarchar(12)
  29433.     declare @command_piece nvarchar(2000)
  29434.     declare @rowguidcolname nvarchar(140)
  29435.     declare @view_type    int
  29436.     declare    @view_name  nvarchar(270)
  29437.     declare @or_after_first nvarchar(100)
  29438.     declare @select_command nvarchar(4000)
  29439.     declare @retcode int 
  29440.     declare @generate_per_article bit 
  29441.     declare @newidstr       nvarchar(40)
  29442.     declare @newid          uniqueidentifier
  29443.  
  29444.     /*
  29445.     **  Security Check
  29446.     */
  29447.     exec @retcode = sp_MSreplcheck_publish
  29448.     if @retcode <> 0 or @@error <> 0
  29449.         return 1
  29450.  
  29451.     /* By default the @generate_per_article is OFF */
  29452.       set @generate_per_article = 0
  29453.  
  29454.       set @new_inactive = 5 /* value of SQLDMOArtStat_New_Inactive */
  29455.       set @new_active = 6 /* value of SQLDMOArtStat_New_Active */
  29456.  
  29457.     if @ctsview IS NULL
  29458.         set @generate_per_article = 1
  29459.     
  29460.     select @retcode = 0
  29461.     set @or_after_first = ''
  29462.  
  29463.     select @pubid = pubid from sysmergepublications where name = @publication 
  29464.         and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name()
  29465.     if @pubid is null
  29466.     BEGIN
  29467.         RAISERROR (20026, 16, -1, @publication)
  29468.         RETURN (1)
  29469.     END
  29470.  
  29471.     select @newid = newid()
  29472.     exec @retcode = dbo.sp_MSguidtostr @newid, @newidstr out
  29473.     if @@ERROR <>0 OR @retcode <> 0
  29474.         return (1)
  29475.     exec @retcode = dbo.sp_MSguidtostr @pubid, @pubidstr out
  29476.     if @@ERROR <>0 OR @retcode <> 0 
  29477.         return (1)
  29478.  
  29479.     -- create the temp tables here since the views are commong to both
  29480.     -- filtered and unfiltered per article contents views
  29481.     /* create temp table to insert into and select commands out of */
  29482.     if @generate_per_article = 1
  29483.     begin
  29484.         /* create temp table to insert into and select commands out of */
  29485.         declare @temp_cts_views table
  29486.         (
  29487.             step int identity NOT NULL,
  29488.             ctsvw sysname collate database_default null, 
  29489.             tablenickname int
  29490.         )
  29491.         if @@ERROR <> 0
  29492.             return (1)
  29493.             
  29494.         select @tablenick = min(nickname) from dbo.sysmergearticles where pubid = @pubid and status<>@new_active and status<>@new_inactive
  29495.         while @tablenick is not null
  29496.         begin
  29497.             select @artid = artid from dbo.sysmergearticles where nickname = @tablenick and pubid = @pubid
  29498.             exec @retcode = dbo.sp_MSguidtostr @artid, @artidstr out
  29499.             if @@ERROR <>0 OR @retcode <> 0 return (1)
  29500.  
  29501.             set @ctsview = 'cont_' + @newidstr + '_' + @artidstr
  29502.             if exists (select * from sysobjects where name=@ctsview and type='V')
  29503.             begin
  29504.                 declare @ownername sysname
  29505.                 declare @viewname sysname
  29506.                 
  29507.                 select @ownername = user_name(uid) from sysobjects where  name=@ctsview
  29508.                 select @viewname = QUOTENAME(@ownername) + '.' + QUOTENAME(@ctsview)
  29509.                 exec ('drop view ' + @viewname)
  29510.                 if @@ERROR<>0 return (1)
  29511.             END
  29512.  
  29513.             -- insert the view name into the temp table created in this proc
  29514.             insert into @temp_cts_views (ctsvw, tablenickname) 
  29515.                                   values(@ctsview, @tablenick)
  29516.  
  29517.             /* Advance to next article and repeat the loop */
  29518.             select @tablenick = min(nickname) from dbo.sysmergearticles where
  29519.                 pubid = @pubid and nickname > @tablenick and status<>@new_active and status<>@new_inactive
  29520.         end
  29521.     end
  29522.     else
  29523.     begin
  29524.         -- this is the regular case (called from sp_MSmakesystableviews)
  29525.         declare @tempcmd table 
  29526.         (
  29527.             phase int NOT NULL, 
  29528.             step int identity NOT NULL,
  29529.             cmdtext nvarchar(4000) collate database_default null
  29530.         )
  29531.     end
  29532.  
  29533.     /* pubidstr is needed in GUID format */
  29534.     set @pubidstr = '''' + convert(nchar(36), @pubid) + ''''
  29535.  
  29536.     
  29537.     /* Check for the no filtering cases */
  29538.     if not exists (select * from sysmergesubsetfilters where pubid = @pubid) and
  29539.        not exists (select * from sysmergearticles where pubid = @pubid and
  29540.                        len(subset_filterclause) > 0)
  29541.     begin
  29542.     -- un filtered case
  29543.         if @generate_per_article = 0
  29544.         begin
  29545.             -- If @generate_per_article = 0, an entire view is returned in @command_piece.
  29546.             set @command_piece = 'create view ' + @ctsview + ' as select * from dbo.MSmerge_contents '
  29547.  
  29548.             --5 and 6 are the new article statuses - they indicate new_inactive and new_active
  29549.             set @command_piece = @command_piece + ' where tablenick in
  29550.                 (select nickname from dbo.sysmergearticles where status<>5 and status<>6 and pubid = ' + @pubidstr + ')' 
  29551.  
  29552.             insert into @tempcmd (phase, cmdtext) values (1, @command_piece)
  29553.         end
  29554.         else
  29555.         begin
  29556.             -- per article contents view for unfiltered publication
  29557.             select @tablenick = min(nickname) from dbo.sysmergearticles where pubid = @pubid and status<>@new_active and status<>@new_inactive
  29558.             while @tablenick is not null
  29559.             begin
  29560.                 if not exists(select * from @temp_cts_views where tablenickname = @tablenick)
  29561.                     return (1)
  29562.                     
  29563.                 select @ctsview = ctsvw from @temp_cts_views where tablenickname = @tablenick
  29564.                 
  29565.                 set @tablenickstr = convert(nchar(12), @tablenick)
  29566.             
  29567.                 set @command_piece = 'create view ' + @ctsview + ' as select * from dbo.MSmerge_contents '
  29568.                 set @command_piece = @command_piece + ' where tablenick = ' + @tablenickstr
  29569.                 
  29570.                 exec @retcode= dbo.sp_executesql @command_piece
  29571.                 if @@error <> 0 or @retcode <> 0 return 1
  29572.  
  29573.                 /* Advance to next article and repeat the loop */
  29574.                 select @tablenick = min(nickname) from dbo.sysmergearticles where
  29575.                     pubid = @pubid and nickname > @tablenick and status<>@new_active and status<>@new_inactive
  29576.             end
  29577.         end        
  29578.         goto Finish
  29579.     end
  29580.  
  29581.     -- filtered case
  29582.     if @generate_per_article = 0
  29583.     begin
  29584.         set @command_piece = 'create view ' + @ctsview + ' as select * from dbo.MSmerge_contents where '
  29585.         insert into @tempcmd (phase, cmdtext) values (1, @command_piece)
  29586.     end            
  29587.  
  29588.     /* Initialize for loop over articles in this publication */
  29589.     select @tablenick = min(nickname) from dbo.sysmergearticles where pubid = @pubid and status<>@new_active and status<>@new_inactive
  29590.     while @tablenick is not null
  29591.     begin
  29592.         if @dynamic_snapshot_views_table_name is null or @dynamic_snapshot_views_table_name = N''
  29593.         begin
  29594.             select @objid = objid, @view_type = view_type, @view_name = object_name(sync_objid) from 
  29595.                 sysmergearticles where pubid = @pubid and nickname = @tablenick 
  29596.         end
  29597.         else
  29598.         begin
  29599.             select @select_command = '
  29600.                 select @objid = sma.objid, 
  29601.                        @view_type = sma.view_type, 
  29602.                        @view_name = dsvt.dynamic_snapshot_view_name 
  29603.                   from sysmergearticles sma
  29604.                 inner join ' + @dynamic_snapshot_views_table_name + ' dsvt 
  29605.                     on dsvt.artid = sma.artid            
  29606.                  where pubid = @pubid 
  29607.                    and nickname = @tablenick'
  29608.             exec sp_executesql @select_command,
  29609.                                N'@objid int output, 
  29610.                                  @view_type int output, 
  29611.                                  @view_name nvarchar(270) output,
  29612.                                  @pubid uniqueidentifier,
  29613.                                  @tablenick int',
  29614.                                @objid = @objid output,
  29615.                                @view_type = @view_type output, 
  29616.                                @view_name = @view_name output,
  29617.                                @pubid = @pubid,
  29618.                                @tablenick = @tablenick  
  29619.             if @@error<>0 return(1)
  29620.         end
  29621.         select @rowguidcolname = name from syscolumns where id = @objid and
  29622.                 columnproperty(id, name, 'isrowguidcol')=1
  29623.  
  29624.         set @rowguidcolname = QUOTENAME(@rowguidcolname)
  29625.         set @view_name = QUOTENAME(@view_name)
  29626.         set @tablenickstr = convert(nchar(12), @tablenick)
  29627.         
  29628.         -- if view_type is non-zero it means that we have a filtered article
  29629.         -- if view_type is 0 it means that we have an unfiltered article.
  29630.         -- the selects we do for the ctsview has to be different for these two cases
  29631.         if @generate_per_article = 0
  29632.         begin
  29633.             if @view_type <> 0
  29634.             begin
  29635.                 set @command_piece = @or_after_first + ' 
  29636.                 (tablenick = ' + @tablenickstr + ' and rowguid in
  29637.                     (select ' + @rowguidcolname + ' from ' + @view_name + '))'
  29638.             end
  29639.             else
  29640.             begin
  29641.                 set @command_piece = @or_after_first + ' 
  29642.                 (tablenick = ' + @tablenickstr + ')'
  29643.             end
  29644.             
  29645.             insert into @tempcmd (phase, cmdtext) values (2, @command_piece)
  29646.         end
  29647.         else
  29648.         begin
  29649.             -- by the time we reach this point we have already pregenerated the view names that should
  29650.             -- be used and stored them in the temp table @temp_cts_views
  29651.             -- check here to make sure that this article exists in the temp table
  29652.             if not exists(select * from @temp_cts_views where tablenickname = @tablenick)
  29653.                 return (1)
  29654.             
  29655.             select @ctsview = ctsvw from @temp_cts_views where tablenickname = @tablenick
  29656.             if @view_type <> 0
  29657.             begin
  29658.                 set @command_piece = 'create view dbo.' + @ctsview + 
  29659.                         ' as select * from dbo.MSmerge_contents where (tablenick = ' + @tablenickstr + ' and rowguid in
  29660.                         (select ' + @rowguidcolname + ' from ' + @view_name + ')) '
  29661.                 exec @retcode= dbo.sp_executesql @command_piece
  29662.                 if @@ERROR <>0 
  29663.                     return (1)
  29664.             end                    
  29665.             else
  29666.             begin
  29667.                 -- we get here if we find an unfiltered article in a publication which has some
  29668.                 -- subset filters
  29669.                 set @command_piece = 'create view dbo.' + @ctsview + 
  29670.                         ' as select * from dbo.MSmerge_contents 
  29671.                         where (tablenick = ' + @tablenickstr + ')'
  29672.                 exec @retcode= dbo.sp_executesql @command_piece
  29673.                 if @@ERROR <>0 
  29674.                     return (1)
  29675.             end
  29676.         end -- end @generate_per_article check
  29677.         
  29678.         /* Advance to next article and repeat the loop */
  29679.         select @tablenick = min(nickname) from sysmergearticles where
  29680.             pubid = @pubid and nickname > @tablenick and status<>@new_active and status<>@new_inactive
  29681.  
  29682.         /* make it so that any subsequent selects in the view are preceded by the word UNION */
  29683.         /* using OR to replace 'UNION ALL', which is equivalent to workaround a bug */
  29684.         set @or_after_first = ' OR '
  29685.     end
  29686.  
  29687. Finish:
  29688.     /* final steps: select out the text and drop the temp table */
  29689.     if @generate_per_article = 0
  29690.     begin
  29691.         select cmdtext from @tempcmd order by phase, step
  29692.     end         
  29693.     else
  29694.     begin
  29695.         /* Select the view names so that the caller can query them so they can be BCP'd out and dropped later */
  29696.         -- to see how this is read and used look at CMergePublication::GenerateContentsBcpFile
  29697.         select ctsvw from @temp_cts_views order by step
  29698.     end
  29699.  
  29700.     return(0)
  29701. go
  29702. exec dbo.sp_MS_marksystemobject sp_MSmakectsview 
  29703. go
  29704. grant exec on dbo.sp_MSmakectsview to public
  29705. go
  29706.  
  29707. create procedure sp_MSinsertgenerationschemachanges
  29708.     @publication sysname
  29709. AS
  29710.     declare @mingen         int
  29711.     declare @lastrecgen        int
  29712.     declare @lastrecguid    uniqueidentifier
  29713.     declare @lastsentgen        int
  29714.     declare @lastsentguid    uniqueidentifier
  29715.     declare @db_name        sysname
  29716.     declare @repid             uniqueidentifier
  29717.     declare @pubid             uniqueidentifier
  29718.     declare @schemaversion  int 
  29719.     declare @schemaguid     uniqueidentifier
  29720.     declare @schematype     int
  29721.     declare @schematext     nvarchar(2000)
  29722.     declare @artid            uniqueidentifier
  29723.     declare @retcode        int
  29724.     set nocount on
  29725.  
  29726.     set @lastrecgen = NULL
  29727.     set @lastsentgen = NULL
  29728.     
  29729.     begin tran
  29730.     save TRAN MSinsertgenerationschemachanges    
  29731.  
  29732.     set @db_name = db_name()
  29733.     select @pubid = pubid from sysmergepublications where name = @publication and publisher = @@SERVERNAME and publisher_db = @db_name
  29734.     if @pubid IS NULL
  29735.         BEGIN
  29736.             RAISERROR (20026, 16, -1, @publication)
  29737.             goto FAILURE
  29738.         END
  29739.  
  29740.     -- security check
  29741.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @pubid=@pubid
  29742.     if @@error <> 0 or @retcode <> 0
  29743.         return 1
  29744.     
  29745.     SELECT @repid = subid FROM sysmergesubscriptions where pubid = @pubid and subid = @pubid
  29746.     if @repid is NULL
  29747.         begin
  29748.             RAISERROR(20021, 16, -1)
  29749.             goto FAILURE
  29750.         end
  29751.  
  29752.     select @mingen = min(generation) from dbo.MSmerge_genhistory where guidlocal = '00000000-0000-0000-0000-000000000000'
  29753.     if @mingen IS NOT NULL
  29754.         select @lastrecgen = max(generation) from dbo.MSmerge_genhistory where generation < @mingen
  29755.     if @lastrecgen IS NOT NULL
  29756.         begin
  29757.             select @lastrecguid = guidsrc from dbo.MSmerge_genhistory where generation = @lastrecgen
  29758.  
  29759.             set @artid = NULL
  29760.             set @schematype = 5 /* last rec gen schema type */
  29761.             select @schematext = 'exec dbo.sp_MSsetlastrecgen ' + '''' + convert(nchar(36), @repid) + ''''  + ',' + '''' + convert(nvarchar(10), @lastrecgen) + '''' + ',' + '''' + convert(nchar(36), @lastrecguid) + ''''
  29762.  
  29763.             if exists (select *    from sysmergeschemachange
  29764.                     where pubid = @pubid 
  29765.                     AND schematype = @schematype)
  29766.                 begin
  29767.                     /* Select the existing schema guid */
  29768.                     select @schemaversion = schemaversion, @schemaguid = schemaguid from sysmergeschemachange
  29769.                         where pubid = @pubid 
  29770.                         AND schematype = @schematype
  29771.                     /*
  29772.                     ** Update the schema change version
  29773.                     */
  29774.                     exec @retcode = dbo.sp_MSupdateschemachange @pubid, @artid, @schemaversion, 
  29775.                         @schemaguid, @schematype, @schematext
  29776.                     if @@error <> 0    or @retcode <> 0
  29777.                         goto FAILURE
  29778.                 end
  29779.             else        
  29780.                 begin
  29781.                     /* Insert the schema change */
  29782.                     select @schemaversion = schemaversion from sysmergeschemachange
  29783.                     if (@schemaversion is NULL)
  29784.                         set @schemaversion = 1
  29785.                     else
  29786.                         select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
  29787.                         
  29788.                     /* generate a new schema guid */
  29789.                     set @schemaguid = newid()
  29790.                     exec @retcode = dbo.sp_MSinsertschemachange @pubid, @artid, @schemaversion, 
  29791.                         @schemaguid, @schematype, @schematext
  29792.                     if @@error <> 0    or @retcode <> 0
  29793.                         goto FAILURE
  29794.                 end                
  29795.  
  29796.         end        
  29797.  
  29798.     select @lastsentgen = max(generation) from dbo.MSmerge_genhistory
  29799.         where guidlocal <> '00000000-0000-0000-0000-000000000000' and (art_nick = 0 or art_nick is NULL or
  29800.             art_nick in (select nickname from sysmergearticles where pubid = @pubid))
  29801.  
  29802.     if @lastsentgen IS NOT NULL
  29803.         begin
  29804.             select @lastsentguid = guidsrc from dbo.MSmerge_genhistory where generation = @lastsentgen
  29805.             set @artid = NULL
  29806.             set @schematype = 6 /* last sent gen schema type */
  29807.             select @schematext = 'exec dbo.sp_MSsetlastsentgen ' + '''' + convert(nchar(36), @repid) + ''''  + ',' + '''' + convert(nvarchar(10), @lastsentgen) + '''' + ',' + '''' + convert(nchar(36), @lastsentguid) + ''''
  29808.  
  29809.             if exists (select *    from sysmergeschemachange
  29810.                     where pubid = @pubid 
  29811.                     AND schematype = @schematype)
  29812.                 begin
  29813.                     /* Select the existing schema guid */
  29814.                     select @schemaversion = schemaversion, @schemaguid = schemaguid from sysmergeschemachange
  29815.                         where pubid = @pubid 
  29816.                         AND schematype = @schematype
  29817.                     /*
  29818.                     ** Update the schema change version
  29819.                     */
  29820.                     exec @retcode = dbo.sp_MSupdateschemachange @pubid, @artid, @schemaversion, 
  29821.                         @schemaguid, @schematype, @schematext
  29822.                     if @@error <> 0    or @retcode <> 0
  29823.                         goto FAILURE
  29824.                 end
  29825.             else        
  29826.                 begin
  29827.                     /* Insert the schema change */
  29828.                     select @schemaversion = schemaversion from sysmergeschemachange
  29829.                     if (@schemaversion is NULL)
  29830.                         set @schemaversion = 1
  29831.                     else
  29832.                         select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
  29833.                         
  29834.                     /* generate a new schema guid */
  29835.                     set @schemaguid = newid()
  29836.                     exec @retcode = dbo.sp_MSinsertschemachange @pubid, @artid, @schemaversion, 
  29837.                         @schemaguid, @schematype, @schematext
  29838.                     if @@error <> 0    or @retcode <> 0
  29839.                         goto FAILURE
  29840.                 end                
  29841.                 
  29842.         end
  29843.     COMMIT TRAN            
  29844.     RETURN 0
  29845.  
  29846. FAILURE:
  29847.     /* UNDONE : This code is specific to 6.X nested transaction semantics */
  29848.     if @@TRANCOUNT > 0
  29849.     begin
  29850.         ROLLBACK TRANSACTION MSinsertgenerationschemachanges
  29851.         COMMIT TRANSACTION
  29852.     end
  29853.     
  29854.     RETURN 1
  29855. go
  29856.        
  29857. exec dbo.sp_MS_marksystemobject sp_MSinsertgenerationschemachanges
  29858. go
  29859.  
  29860. grant exec on dbo.sp_MSinsertgenerationschemachanges to public
  29861. go
  29862.  
  29863. CREATE PROCEDURE sp_MSalreadyhavegeneration
  29864.     (@genguid uniqueidentifier, @subscribernick int)
  29865. as
  29866.     declare @nicknames varbinary(1000)
  29867.     declare @offset int
  29868.     declare @retcode int
  29869.  
  29870.     -- security check
  29871.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck 
  29872.     if @@error <> 0 or @retcode <> 0
  29873.         return 1
  29874.     
  29875.     /*
  29876.     ** Check input parameter
  29877.     */
  29878.     if (@genguid is null)
  29879.         begin
  29880.             RAISERROR(14043, 16, -1, '@genguid')
  29881.             return (1)
  29882.         end
  29883.  
  29884.     select @nicknames = nicknames from dbo.MSmerge_genhistory where guidsrc = @genguid
  29885.     if @nicknames is null
  29886.         begin
  29887.             -- what is the appropriate error to return?
  29888.             RAISERROR(21333, 16, -1)
  29889.             return (1)
  29890.         end
  29891.  
  29892.     set @offset = 1
  29893.     while @offset < len(@nicknames)
  29894.         begin
  29895.             -- If the subscriber nickname is already in the list just return
  29896.             if (convert(int, substring(@nicknames, @offset, 4)) = @subscribernick)
  29897.                 return (0)
  29898.             set @offset = @offset + 4
  29899.         end
  29900.     -- Subscriber nickname is not in the array.  Add it so that we won't send this gen
  29901.     -- back down in the return message.  (Would waste bandwidth...)
  29902.     set @nicknames = convert(binary(4), @subscribernick) + @nicknames
  29903.     update dbo.MSmerge_genhistory set nicknames = @nicknames where guidsrc = @genguid
  29904.     
  29905.     return (0)
  29906. go
  29907. exec dbo.sp_MS_marksystemobject sp_MSalreadyhavegeneration
  29908. go
  29909. grant exec on dbo.sp_MSalreadyhavegeneration to public
  29910. GO
  29911.  
  29912. CREATE PROCEDURE sp_MSgettablecontents 
  29913.     @pubid uniqueidentifier
  29914. as 
  29915.     declare @tablenick             int
  29916.     declare @new_active            int
  29917.     declare @new_inactive        int
  29918.     declare @artname            sysname
  29919.     declare @view_name            nvarchar(60)
  29920.     declare @rowguidcolname        sysname
  29921.     declare @sync_viewname        sysname
  29922.     declare @quoted_sync_viewname nvarchar(144)
  29923.     declare @quoted_view_name    nvarchar(144)
  29924.     declare @nickname            int
  29925.     declare @objid                 int
  29926.     
  29927.     declare @tablenickstr nvarchar(12)
  29928.     
  29929.     select @new_inactive = 5 --special article status for adding article after snapshot
  29930.     select @new_active = 6      --special article status for adding article after snapshot
  29931.     
  29932.     select Top 1 @tablenick = nickname, @sync_viewname=object_name(sync_objid), @objid=objid, @artname=name
  29933.         from sysmergearticles where pubid = @pubid and (status=@new_inactive or status=@new_active)
  29934.                                 order by nickname ASC
  29935.     while @objid is not null
  29936.         begin
  29937.             set @tablenickstr = convert(nchar(12), @tablenick)
  29938.             select @rowguidcolname = name from syscolumns where id = @objid and columnproperty(id, name, 'isrowguidcol')=1
  29939.             select @view_name='MSmerge_contents_' + @artname
  29940.             select @quoted_view_name=QUOTENAME(@view_name)
  29941.             --Must drop the view (if exists) and recreate
  29942.             if exists (select * from sysobjects where name=@view_name and xtype = 'V')
  29943.             begin                
  29944.                 exec ('drop view ' + @quoted_view_name)
  29945.             end
  29946.             select @quoted_sync_viewname=QUOTENAME(@sync_viewname)
  29947.             exec('create view ' + @quoted_view_name + 
  29948.                 ' as select * from dbo.MSmerge_contents where (tablenick = ' + @tablenickstr + ' and rowguid in
  29949.                         (select ' + @rowguidcolname + ' from ' + @quoted_sync_viewname + '))')
  29950.  
  29951.             select @objid = NULL
  29952.             select Top 1 @tablenick = nickname,@sync_viewname=object_name(sync_objid), @objid=objid, @artname=name from sysmergearticles 
  29953.                 where pubid = @pubid and nickname>@tablenick and (status=@new_inactive or status=@new_active) 
  29954.                     order by nickname ASC
  29955.             insert #temp_table_for_systable_view(contentsview) values(@view_name)        
  29956.         end    
  29957. go
  29958.  
  29959. exec dbo.sp_MS_marksystemobject sp_MSgettablecontents
  29960. go
  29961.  
  29962.  
  29963. CREATE PROCEDURE sp_MSdelgenzero
  29964. as
  29965.     declare @retcode int
  29966.  
  29967.     -- security check
  29968.     exec @retcode = dbo.sp_MSrepl_PAL_rolecheck 
  29969.     if @@error <> 0 or @retcode <> 0
  29970.         return 1
  29971.  
  29972.     delete from dbo.MSmerge_contents where generation = 0 or generation = 1
  29973. go
  29974.  
  29975. exec dbo.sp_MS_marksystemobject sp_MSdelgenzero
  29976. go
  29977. grant exec on dbo.sp_MSdelgenzero to public
  29978. GO
  29979.  
  29980. --
  29981. -- Name: sp_MSmakedynsnapshotvws
  29982. --
  29983. -- Description: This procedure generates temporary sync-views on top of 
  29984. --              table articles specific to a particular dynamic filter login by
  29985. --              replacing all occurrances of the suser_sname() intrinsic 
  29986. --              function in the regular article sync-views with the specified
  29987. --              dynamic filter login value.
  29988. --
  29989. -- Parameters: @publication sysname 
  29990. --             @dynamic_filter_login sysname 
  29991. --                    
  29992. -- Notes: This procedure should be used by dynamic snapshot processing
  29993. --        only. A valid regular snapshot is assumed to have been generated
  29994. --        by the time the snapshot agent calls this procedure. If the specified
  29995. --        @dynamic_filter_login is empty or null, the current value
  29996. --        of suser_sname() will be used.
  29997. --
  29998. -- Result: sysname - article_name
  29999. --         sysname - dynamic_snapshot_view_name
  30000. --         The result set basically describes the mapping between articles and
  30001. --         the dynamic snapshot views to be used for the dynamic snapshot 
  30002. --         generation session that initiated the call. The exceptions being the
  30003. --         'dynamic snapshot view name' column of the first row is actually the
  30004. --         name of the global temporary table for tracking the dynamic snapshot
  30005. --         while the 'dynamic snapshot view name' column of the 2nd row is 
  30006. --         actually the owner name of all the generated dynamic snapshot 
  30007. --         views. (Note: all generated views belong to the same owner)       
  30008. --
  30009. -- Returns: 0 - succeeded
  30010. --          1 - failed
  30011. --
  30012. -- Security: Execute permission of this procedure is granted to public. A 
  30013. --           procedural security check is made inside the stored procedure 
  30014. --           to make sure that the caller is either a member of the 
  30015. --           'sysadmin' server role or the 'db_owner' database role.
  30016. --          
  30017. raiserror('Creating procedure sp_MSmakedynsnapshotvws', 0,1)
  30018. go
  30019. create procedure sp_MSmakedynsnapshotvws(
  30020.     @publication sysname, 
  30021.     @dynamic_filter_login sysname,
  30022.     @dynamic_snapshot_views_table_name sysname = NULL
  30023.     )
  30024. as
  30025. begin
  30026.     set nocount on
  30027.     declare @retcode int
  30028.     declare @string_literalized_dynamic_filter_login nvarchar(4000)
  30029.     declare @articles_cursor_allocated bit, 
  30030.             @articles_cursor_opened bit
  30031.     declare @pubid uniqueidentifier
  30032.  
  30033.     select @articles_cursor_allocated = 0
  30034.     select @articles_cursor_opened = 0
  30035.     select @retcode = 0
  30036.     -- Security check
  30037.     exec @retcode = sp_MSreplcheck_publish
  30038.     if @retcode <> 0 or @@error <> 0
  30039.         return 1
  30040.  
  30041.     if @dynamic_filter_login is null or @dynamic_filter_login = N''
  30042.     begin
  30043.         select @dynamic_filter_login = suser_sname()
  30044.     end
  30045.     if @@error<>0
  30046.     begin
  30047.         return 1
  30048.     end
  30049.     select @string_literalized_dynamic_filter_login = 
  30050.         fn_replmakestringliteral(@dynamic_filter_login) collate database_default
  30051.     
  30052.     -- Compute the proper view creation order, code is copied from sp_MSpublicationview
  30053.     declare @progress int
  30054.     declare @article_level int
  30055.     select @progress = 1
  30056.     select @article_level = 0
  30057.     select @pubid = pubid 
  30058.       from sysmergepublications 
  30059.     where upper(publisher) = upper(@@servername)
  30060.       and publisher_db = db_name()
  30061.       and name = @publication
  30062.     if @pubid is null 
  30063.     begin
  30064.         raiserror(20026,11,-1,@publication)
  30065.     end
  30066.     create table #creation_order
  30067.     (
  30068.     creation_order int identity not null,
  30069.     art_nick int not null,
  30070.     article_level int not null    
  30071.     )
  30072.     if @@error<>0
  30073.     begin
  30074.         return 1
  30075.     end
  30076.     
  30077.     while @progress > 0
  30078.     begin
  30079.         insert into #creation_order(art_nick, article_level)
  30080.             select nickname, @article_level 
  30081.               from sysmergearticles
  30082.              where pubid=@pubid 
  30083.                and nickname not in (select art_nick from #creation_order)
  30084.                and nickname not in
  30085.                     (select art_nickname from sysmergesubsetfilters
  30086.                       where pubid=@pubid and join_nickname not in
  30087.                         (select art_nick from #creation_order))
  30088.         select @progress = @@rowcount
  30089.         select @article_level = @article_level + 1
  30090.     end
  30091.  
  30092.     -- Create temp table for storing the view definitions and 
  30093.     -- also for acting as a symbol table for views
  30094.     create table #view_defs_and_syms  
  30095.     (
  30096.         creation_order int identity,
  30097.         original_view_name sysname collate database_default,
  30098.         dynamic_snapshot_view_name sysname collate database_default,
  30099.         dynamic_snapshot_view_definition nvarchar(3500) collate database_default
  30100.     )      
  30101.     if @@error<>0
  30102.     begin
  30103.         return 1
  30104.     end
  30105.     -- By the time this procedure is called by the snapshot agent, a regular
  30106.     -- snapshot is assumed to have been generated.
  30107.     -- The specified publication is assumed to have dynamic filtering enabled        
  30108.     -- Open a transaction to make sure that no stale temporary views
  30109.     -- can be lying around for longer than they have to.  
  30110.     
  30111.     begin transaction
  30112.     save transaction sp_MSmakedynsnapshotartvws
  30113.  
  30114.     -- Create a global temporary table to track the sync-views
  30115.     -- that we are about to create here.
  30116.     if @dynamic_snapshot_views_table_name is NULL
  30117.     begin
  30118.         select @dynamic_snapshot_views_table_name = N'##DYN_VIEWS_' + 
  30119.             replace(convert(nvarchar(36), newid()), N'-', N'_')
  30120.              
  30121.         exec('create table ' + @dynamic_snapshot_views_table_name + '
  30122.               (
  30123.               artid           uniqueidentifier primary key,
  30124.               dynamic_snapshot_view_name sysname not null unique
  30125.               )')
  30126.         if @@error<>0
  30127.         begin
  30128.             goto Failure
  30129.         end
  30130.     end
  30131.  
  30132.     declare hArticles cursor local fast_forward for
  30133.     select artid, sync_objid 
  30134.       from sysmergearticles sma
  30135.     inner join #creation_order co 
  30136.         on sma.nickname = co.art_nick
  30137.      where sma.pubid = @pubid
  30138.     order by co.creation_order asc
  30139.     if @@error<>0
  30140.     begin
  30141.         goto Failure
  30142.     end
  30143.     select @articles_cursor_allocated = 1
  30144.     open hArticles    
  30145.     if @@error<>0
  30146.     begin
  30147.         goto Failure
  30148.     end
  30149.     select @articles_cursor_opened = 1
  30150.  
  30151.     declare @sync_objid int
  30152.     declare @artid uniqueidentifier
  30153.     declare @dynamic_snapshot_view_name sysname
  30154.     declare @original_view_name sysname 
  30155.     declare @insert_command nvarchar(4000)
  30156.     declare @script_view_command nvarchar(4000)
  30157.     declare @min_id int
  30158.     declare @db_name sysname
  30159.     declare @original_view_definition nvarchar(4000)
  30160.  
  30161.     select @db_name = db_name()
  30162.  
  30163.     -- Stage 1: Build up the symbol table with 
  30164.     -- regular sync view definitions
  30165.     fetch hArticles into @artid, @sync_objid
  30166.     
  30167.     while (@@fetch_status<>-1)
  30168.     begin
  30169.         -- Get name of the original sync view
  30170.         select @original_view_name = object_name(@sync_objid)
  30171.  
  30172.         -- Construct name for the dynamic snapshot view        
  30173.         select @dynamic_snapshot_view_name = N'DYN_VIEW_' + 
  30174.             replace(convert(nvarchar(36), newid()), N'-', N'_')
  30175.  
  30176.         -- Insert a row into the symbol and view def table 
  30177.         -- for further processing 
  30178.         select @original_view_definition = text 
  30179.           from dbo.syscomments
  30180.          where id = @sync_objid
  30181.  
  30182.         insert #view_defs_and_syms 
  30183.         values (quotename(@original_view_name), 
  30184.                 @dynamic_snapshot_view_name, 
  30185.                 @original_view_definition) 
  30186.         if @@error<>0
  30187.         begin
  30188.             goto Failure
  30189.         end
  30190.     
  30191.         select @insert_command = N'insert ' + @dynamic_snapshot_views_table_name + ' values (@artid, @dynamic_snapshot_view_name)'
  30192.         -- Insert the mapping into the global temp table
  30193.         exec @retcode = sp_executesql
  30194.             @insert_command,
  30195.             N'@artid uniqueidentifier, @dynamic_snapshot_view_name sysname',
  30196.             @artid = @artid,
  30197.             @dynamic_snapshot_view_name = @dynamic_snapshot_view_name
  30198.  
  30199.         if @@error<>0 or @retcode<>0
  30200.         begin
  30201.             goto Failure
  30202.         end
  30203.  
  30204.         -- Insert the view name into the global tracking table so it is 
  30205.         -- guaranteed to be cleaned up properly 
  30206.         insert MSdynamicsnapshotviews values (@dynamic_snapshot_view_name)
  30207.         if @@error<>0
  30208.         begin
  30209.             goto Failure
  30210.         end
  30211.  
  30212.         fetch hArticles into @artid, @sync_objid   
  30213.     end
  30214.     close hArticles
  30215.     select @articles_cursor_opened = 0
  30216.     deallocate hArticles
  30217.     select @articles_cursor_allocated = 0
  30218.     -- Stage 2: Fix-up all the internal references to non-dynamic snapshot
  30219.     --          views inside the dynamic snapshot view definitions and
  30220.     --          create the views along the way.
  30221.  
  30222.     -- Cursor state variables for ensuring proper cursor cleanup
  30223.     declare @viewdefs_cursor_allocated bit,
  30224.             @viewdefs_cursor_opened bit,
  30225.             @symbols_cursor_allocated bit,
  30226.             @symbols_cursor_opened bit
  30227.  
  30228.     declare @dynamic_snapshot_view_definition nvarchar(4000)
  30229.     declare @dynamic_snapshot_view_name_symbol sysname
  30230.     declare @qualified_dynamic_snapshot_view_name nvarchar(4000)
  30231.  
  30232.     select @viewdefs_cursor_allocated = 0,
  30233.            @viewdefs_cursor_opened = 0,
  30234.